我做错了什么?
unset list
list=("A" "B" "C")
/bin/sh -c "for i in `seq 1 ${#list[@]}` ; do echo $i ; done "
它应该返回:
1
2
3
代替:
/bin/sh: -c: line 1: syntax error near unexpected token `2'
/bin/sh: -c: line 1: `2'
在您的原始代码中,您传递给的双引号字符串/bin/sh
在调用sh
. 特别是,涉及的命令替换seq
和参数$i
都被扩展了。结果,您得到以下信息(您可以set -x
在运行代码之前通过调用来确认):
for i in 1
2
3 ; do echo ; done
1 之后的换行符被视为for
将迭代的序列的终止。此时,sh
会期望关键字do
,但会看到2
。
解决此问题的一种方法是,假设您确实需要将字符串传递给 shell 的另一个实例,即告诉seq
使用不同的分隔符(例如空格)。您还需要转义美元符号,$i
以便它由子 shell 评估,而不是当前 shell。
unset list
list=("A" "B" "C")
/bin/sh -c "for i in `seq -s' ' 1 ${#list[@]}` ; do echo \$i ; done "
这将适用于sh
,因为子shell 看不到数组,无论如何它都不会理解。sudo_O 提供了一个不同的答案,它涉及保护传递给的整个字符串sh
,并包括该list
字符串中的定义,以便它在子shell中可见。请注意,您sh
必须是 shell,例如bash
,因为 POSIXsh
不支持数组,正如 jordanm 所指出的那样。
@chepner 给了你正确的答案。
顺便说一句,您也可以像这样缩短命令(不涉及进一步的 shell)
unset list
list=("A" "B" "C")
for i in `seq 1 ${#list[@]}` ; do echo $i ; done
list
生成子shell时不会定义 数组,因此它没有长度:
for i in `seq 1 ${#list[@]}`
被视为:
for i in seq 1 0
看:
$ sh -c 'echo ${#list[@]}'
0
并且seq 1 0
不产生任何输出,因此看不到任何结果。
list
在当前 shell 中设置并打印出每个值:
$ list=("A" "B" "C")
$ for i in `seq 1 ${#list[@]}`;do echo $i;done
1
2
3
或者list
在子shell中定义:
$ sh -c 'list=("A" "B" "C");for i in `seq 1 ${#list[@]}`;do echo $i;done'
1
2
3