我有点卡住了。我的任务是以相反的顺序打印脚本的参数,除了第三个和第四个。
我所拥有的是这段代码:
#!/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 致敬),我正在寻找一种没有它的解决方案,但我找不到。
如何动态定义参数的位置?
PS:不,这不是作业,我正在为考试学习 shell,所以我尝试解决旧的考试。
答案1
eval
是通过动态选择的位置来访问位置参数的唯一可移植方式。如果您显式循环索引而不是值(您没有使用),您的脚本会更清晰。请注意expr
,除非您希望脚本在古董 Bourne shell 中运行,否则您不需要;$((…))
算术是 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
答案2
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
您还可以使用函数代替专用脚本。
答案3
假设位置参数不包含换行符:
[ "$#" -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
答案4
和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>