使用Bash's arrays,我可以将列表存储到数组变量中并迭代元素,同时保持带引号的字符串包含空格或特殊字符:
LIST=(--foo --bar --baz "test 1 2 3")
for item in "${LIST[@]}"; do
echo "$item"
done
输出是:
--foo
--bar
--baz
test 1 2 3
我有一个使用此功能的脚本,不幸的是需要将其移植到使用Busybox的灰(不支持数组)。我正在试图找出一种存储列表的好方法,其中某些项可能会有空格,同时仍然保留列表中正确数量的元素。
这不起作用(例如(错误地将test 1 2 3
拆分为单独的项目):
LIST='--foo --bar --baz "test 1 2 3"'
for item in $LIST; do
echo "$item"
done
输出是:
--foo
--bar
--baz
"test
1
2
3"
一个idea I found on the Busybox mailing list是使用set --
替换位置参数:
set -- --foo --bar --baz "test 1 2 3"
for item in "$@"; do
echo "$item"
done
输出正确:
--foo
--bar
--baz
test 1 2 3
但是,这个构造破坏了位置参数列表($@
),此脚本也使用。
有没有合理的方法我可以吃蛋糕并吃掉它,并在非Bash sh
变体中模拟多个任意数组?
答案 0 :(得分:4)
您可以在其中声明一个带有\n
的变量:
list='--foo\n--bar\n--baz\n"test 1 2 3"'
# then iterate it using
echo -e "$list" | while read -r line; do echo "line=[$line]"; done
<强>输出:强>
line=[--foo]
line=[--bar]
line=[--baz]
line=["test 1 2 3"]
答案 1 :(得分:2)
大多数shell提供某种数组的原因是因为你不能使用扁平字符串安全地模拟它们。如果您可以从脚本的其余部分中隔离需要数组的代码,则可以在子shell中执行它,以便在子shell退出后可以恢复位置参数。
( # Nothing in here can rely on the "real" positional
# parameters, unless you can fsave them to a fixed set of indiviual
# parameters first.
first_arg=$1 # etc
set -- --foo --bar --baz "test 1 2 3"
for item in "$@"; do
echo "$item"
done
# Any other parameters you set or update will likewise revert
# to their former values now.
)
答案 2 :(得分:0)
聚会晚了几年,但是...我确实找到了一种方法,而又不会破坏$@
,并且甚至可以处理恶意输入。
输入:
SSH_ORIGINAL_COMMAND='echo "hello world" foo '"'"'bar'"'"'; sudo ls -lah /; say -v Ting-Ting "evil cackle"'
(我最初在那里有一个rm -rf
,但后来我意识到,在测试脚本的变体时,这将是灾难的根源)
完美地转换为安全参数:
# Note: DO NOT put IFS= on its own line (that would overwrite it: bad)
IFS=$'\r\n' GLOBIGNORE='*' args=($(echo "$SSH_ORIGINAL_COMMAND" | \
xargs bash -c 'for arg in "$@"; do echo "$arg"; done'))
这为您提供了一个不错的${args[@]}
,您可以像$@
一样使用它:
for arg in "${args[@]}"
do
echo "$arg"
done
输出:
hello world
foo
bar;
sudo
rm
-rf
/;
say
-v
Ting-Ting
evil cackle
我希望这对像我这样的未来围观者有帮助。