如何在Bourne shell中的变量中存储带引号的字符串列表? (没有Bash数组)

时间:2016-07-05 18:28:05

标签: shell sh busybox quoting ash

使用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变体中模拟多个任意数组?

3 个答案:

答案 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)

xargs +子shell

聚会晚了几年,但是...我确实找到了一种方法,而又不会破坏$@,并且甚至可以处理恶意输入

输入:

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

我希望这对像我这样的未来围观者有帮助。