나는 약간 붙어있다. 내 임무는 세 번째와 네 번째를 제외하고 인수를 스크립트에 역순으로 인쇄하는 것입니다.
내가 가진 것은이 코드입니다.
#!/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 인사)을 싫어함에 따라 솔루션이없는 솔루션을 찾고 있지만 찾을 수 없습니다.
인수의 위치를 동적으로 정의하려면 어떻게해야합니까?
추신 : 숙제가 아닙니다. 시험을 위해 쉘을 배우고 있으므로 오래된 시험을 풀려고합니다.
답변
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
답변
나는 이것을하는 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
전용 스크립트 대신 함수를 사용할 수도 있습니다.
답변
이것은 정확하고 위험하지 않은 eval의 사용입니다. 당신은 당신이하고있는 내용을 완벽하게 제어 eval
합니다.
여전히 기분이 좋지 않으면 이식성에 신경 쓰지 않는다면 Bash의 ${!i}
간접 구문을 사용할 수 있습니다 .
답변
위치 매개 변수에 개행 문자가 포함되지 않았다고 가정하십시오.
[ "$#" -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
답변
로 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>
답변
기본적으로 모든 쉘 :
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
답변
declare -a argv=( "$@" )
for (( i=$((${#argv[@]}-1)) ; i>=0 ; i=$(($i-1)) )) ; do
echo "${argv[$i]}"
# use "${argv[$i]}" in here...
done