Answers:
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
是命名参数或数字(表示位置参数)时,此方法有效。在使用它时,您可以使用其他bash便利功能。
for ((i=$#; i>0; i--)); do
if ((i != 3 && i != 4)); then
echo "Parameter $i is ${!i}"
fi
done
eval
这不是Ryan所展示的唯一可移植的方法。
我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
您也可以使用函数代替专用脚本。
$#
?可以是非负整数吗?
local arg=$1
这是对eval的正确且非危险的使用。您可以完全控制要播放的内容eval
。
如果它仍然给您带来不好的感觉,那么如果您不关心可移植性,则可以使用Bash的${!i}
间接语法。
${!i}
这不是标准语法的一部分吗?
与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
这是一个shell函数,可以alias
为您设置一个shell ,该shell 将向前或向后打印参数:
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
...将它们反向打印。
因为别名不存储任何文字值,所以当实际的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
for ((i = $# - 1; i >= 0; i--))
arg
因为它们的订购正确且没有相反的顺序。对于的使用expr
,我仅限于使用标准。