쉘 인수를 역순으로 인쇄


12

나는 약간 붙어있다. 내 임무는 세 번째와 네 번째를 제외하고 인수를 스크립트에 역순으로 인쇄하는 것입니다.

내가 가진 것은이 코드입니다.

#!/bin/bash

i=$#
for arg in "$@"
do
    case $i
    in
        3) ;;
        4) ;;
        *) eval echo "$i. Parameter: \$$i";;
    esac
    i=`expr $i - 1`
done

eval (PHP 인사)을 싫어함에 따라 솔루션이없는 솔루션을 찾고 있지만 찾을 수 없습니다.

인수의 위치를 ​​동적으로 정의하려면 어떻게해야합니까?

추신 : 숙제가 아닙니다. 시험을 위해 쉘을 배우고 있으므로 오래된 시험을 풀려고합니다.

답변:


13

eval동적으로 선택된 위치로 위치 매개 변수에 액세스 할 수있는 유일한 방법입니다. 사용하지 않는 값 대신 인덱스를 명시 적으로 반복하면 스크립트가 더 명확 해집니다. expr골동품 Bourne 쉘에서 스크립트를 실행 하지 않는 한 필요하지 않습니다 . $((…))산술은 POSIX에 있습니다. 사용 eval가능한 가장 작은 조각으로 제한하십시오 . 예를 들어을 사용하지 말고 eval echo값을 임시 변수에 지정하십시오.

i=$#
while [ "$i" -gt 0 ]; do
  if [ "$i" -ne 3 ] && [ "$i" -ne 2 ]; then
    eval "value=\${$i}"
    echo "Parameter $i is $value"
  fi
  i=$((i-1))
done

bash에서 ${!i}이름이 인 매개 변수의 값을 의미하는 데 사용할 수 있습니다 $i. $i이름이 지정된 매개 변수 또는 숫자 (위치 매개 변수를 나타내는) 일 때 작동합니다 . 당신이 그것을하는 동안, 당신은 다른 배쉬 편의 기능을 사용할 수 있습니다.

for ((i=$#; i>0; i--)); do
  if ((i != 3 && i != 4)); then
    echo "Parameter $i is ${!i}"
  fi
done

나는 arg그들이 올바르게 주문되고 반대로되지 않기 때문에 사용할 수 없습니다 . 의 사용으로 expr표준 만 사용하도록 제한되어 있습니다.
WarrenFaith

1
@WarrenFaith 스크립트가로 시작 #!/bin/bash하면 ${!i}및 을 사용할 수 있습니다 (()). 표준 sh 를 고수하려면 사용할 수 없지만 사용할 수 $((…))는 있습니다.
Gilles 'SO- 악마 그만'

좋아, 나는이 :)와 함께 작동 할 수 있다고 생각
WarrenFaith

골동품 Bourne 쉘은 어쨌든 $ 9 이상의 위치 매개 변수에 액세스 할 수 없습니다.
Stéphane Chazelas

1
evalRyan이 보여준 유일한 휴대용 방법 은 아닙니다 .
Stéphane Chazelas 2016 년

7

나는 이것을하는 reverse경로에 스크립트 를 유지한다 .

#!/bin/sh

if [ "$#" -gt 0 ]; then
    arg=$1
    shift
    reverse "$@"
    printf '%s\n' "$arg"
fi

사용법 예 :

$ reverse a b c '*' '-n'
-n
*
c
b
a

전용 스크립트 대신 함수를 사용할 수도 있습니다.


지금까지 게시 된 다른 답변과 달리 하나는 Bourne 쉘에서도 작동합니다 (요즘 해당 쉘을 사용할 이유가 없음)
Stéphane Chazelas

@ StéphaneChazelas : 왜 인용 $#하는가? 음수가 아닌 정수 이외의 것이 될 수 있습니까?
G-Man, 'Reinstate

2
@ G-Man, 변수를 따옴표로 묶지 않은 채로두면 split + glob 연산자가 호출됩니다. 여기에서 왜 호출하고 싶은지 이유가 없습니다. 그것은 변수의 내용과 관련이 없습니다. unix.stackexchange.com/a/171347 을 참조하십시오 . 또한 일부 쉘 (예 : 대시, 포쉬)은 여전히 ​​환경에서 IFS를 상속합니다.
Stéphane Chazelas

나는 안드로이드에, 내가 선언 한 것으로 나타local arg=$1
starfry

2

이것은 정확하고 위험하지 않은 eval의 사용입니다. 당신은 당신이하고있는 내용을 완벽하게 제어 eval합니다.

여전히 기분이 좋지 않으면 이식성에 신경 쓰지 않는다면 Bash의 ${!i}간접 구문을 사용할 수 있습니다 .


그래서 ${!i}표준 문법의 일부가 아닙니다?
WarrenFaith

아니, 그것은 Bashism입니다. POSIX 매개 변수 확장은 다음과 같습니다. pubs.opengroup.org/onlinepubs/009695399/utilities/…
Shawn J. Goff

2

위치 매개 변수에 개행 문자가 포함되지 않았다고 가정하십시오.

[ "$#" -gt 0 ] && printf '%s\n' "$@" | #print in order
sed '3,4 d' |                          #skip 3 and 4
tac                                    #reverse (try tail -r on
                                       #non-GNU systems).

테스트:

set 1 2 3 4 5 6
printf '%s\n' "$@" | 
sed '3,4 d' |
tac

테스트 출력 :

6
5
2
1

1

zsh:

$ set a 'foo bar' c '' '*'
$ printf '<%s>\n' "${(Oa)@}"
<*>
<>
<c>
<foo bar>
<a>

Oa팽창에 따라 배열 요소 정렬 파라미터 확장 플래그이다 역방향 배열 인덱스.

3과 4를 제외하려면 :

$ printf '<%s>\n' "${(Oa)@[5,-1]}" "${(Oa)@[1,2]}"
<*>
<foo bar>
<a>

0

기본적으로 모든 쉘 :

printf '{ PS4=\${$(($#-$x))}; } 2>&3; 2>&1\n%.0s' |
x=LINENO+1 sh -sx "$@" 3>/dev/null

그리고 서브 쉘을 사용할 필요 가 없습니다 . 예를 들면 다음과 같습니다.

set -x a b c
{ last= PS4=\${last:=\${$#}}; set +x; } 2>/dev/null
echo "$last"

...인쇄물...

c

그리고 여기 alias에 인수를 앞뒤로 인쇄 할 쉘 을 설정할 수있는 쉘 함수가 있습니다 :

tofro() case $1 in (*[!0-9]*|'') ! :;;(*) set "$1"
        until   [ "$1" -eq "$(($#-1))" ]    &&
                shift && alias args=":; printf \
            \"%.\$((\$??\${#*}:0))s%.\$((!\$??\${#*}:0))s\n\" $* "
        do      [ "$#" -gt 1 ] &&
                set "$@ \"\${$#}\" " '"${'"$((1+$1-$#))"'}"' ||
                set "$1" '"$1" "${'"$1"'}"'
        done;   esac

인수에 대한 리터럴 값을 저장하려고 시도하지 않고 다음과 같은 문자열을 args alias:

:;printf    "%.$(($??${#*}:0))s%.$((!$??${#*}:0))s\n" \
            "$1" "${3}" "${2}"  "${2}" "${3}"  "${1}"

... 따라서 앞뒤로 매개 변수에 대한 참조 만 저장합니다. 인수로 주어진 수만큼 카운트를 저장합니다. 그리고 위와 같이 alias생성되었습니다 :

tofro 3

printf의 동작은 이전 명령의 반환 값을 기반으로 영향을받습니다. 항상 :null 명령이므로 일반적으로 true입니다. printf인쇄 할 때마다 인수의 절반을 건너 뜁니다. 기본적으로 인수는 가장 작은 숫자에서 가장 큰 숫자로 인쇄됩니다. 그러나 당신이 방금 할 경우 :

! args

... 반대로 인쇄합니다.

별명은 리터럴 값을 저장하지 않으므로 실제 인수는 변경 될 수 있지만 정적 값은 그대로 유지되지만 여전히 많은 수를 참조합니다. 예를 들면 다음과 같습니다.

set one two three
tofro 3
args; ! args
shift; args; ! args

... 인쇄 ...

one
two
three
three
two
one
two
three


three
two

그러나 별칭 재설정은 다음과 같이 수행 할 수 있습니다.

tofro 2
args; ! args

... 그래서 인쇄합니다 ...

two
three
three
two

-3
declare -a argv=( "$@" )
for (( i=$((${#argv[@]}-1)) ; i>=0 ; i=$(($i-1)) )) ; do
        echo "${argv[$i]}"
        # use "${argv[$i]}" in here...
done

2
전혀 설명이 없습니다. 나에게서 공감. 코드의 기능을 설명하면 마음이 바뀔 수 있습니다.
WarrenFaith 2016 년

3
로 단순화 할 수있다for ((i = $# - 1; i >= 0; i--))
스테판 Chazelas가

환각입니까? 나는 질문에서 "제 3과 제 4를 제외하고 논증을 인쇄하라"는 말을 보았다고 생각했다.
G-Man, 'Reinstate

1
@ G-Man, 제목은 "인수 인수를 반대로 인쇄합니다"라고 말하며 eval을 사용하지 않고 대답합니다. 그것에서 3과 4를 제외하는 것은 사소한 것입니다. 다운 보트가 정당하다고 생각하지 않습니다. 그것은 또한 자명하다 (내가 말했듯이 상당히 단순화 될 수 있지만).
Stéphane Chazelas 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.