Bash 在shell命令中使用循环时出现错误消息
我做错了什么Bash 在shell命令中使用循环时出现错误消息,bash,loops,sh,subshell,Bash,Loops,Sh,Subshell,我做错了什么 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之前由shell处理。特别是,涉
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
之前由shell处理。特别是,涉及seq
的命令替换和参数$i
都被展开。因此,您会得到以下结果(您可以在运行代码之前通过调用set-x
进行确认):
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指出的那样。在原始代码中,传递给/bin/sh
的双引号字符串在调用sh
之前由shell处理。特别是,涉及seq
的命令替换和参数$i
都被展开。因此,您会得到以下结果(您可以在运行代码之前通过调用set-x
进行确认):
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
,因为正如jordanm所指出的,POSIXsh
不支持数组。在生成子shell时,将不会定义数组列表
,因此它没有长度:
for i in `seq 1 ${#list[@]}`
被视为:
for i in seq 1 0
见:
并且seq 1 0
不产生任何输出,因此看不到任何结果
设置列表
并打印当前shell中的每个值:
$ list=("A" "B" "C")
$ for i in `seq 1 ${#list[@]}`;do echo $i;done
1
2
3
或者在子shell中定义列表
:
$ sh -c 'list=("A" "B" "C");for i in `seq 1 ${#list[@]}`;do echo $i;done'
1
2
3
生成子shell时,将不会定义数组
列表
,因此它将没有长度生成:
for i in `seq 1 ${#list[@]}`
被视为:
for i in seq 1 0
见:
并且seq 1 0
不产生任何输出,因此看不到任何结果
设置列表
并打印当前shell中的每个值:
$ list=("A" "B" "C")
$ for i in `seq 1 ${#list[@]}`;do echo $i;done
1
2
3
或者在子shell中定义列表
:
$ sh -c 'list=("A" "B" "C");for i in `seq 1 ${#list[@]}`;do echo $i;done'
1
2
3
@切普纳给了你正确的答案 顺便说一下,您也可以像这样缩短命令(不再涉及shell)
@切普纳给了你正确的答案 顺便说一下,您也可以像这样缩短命令(不再涉及shell)
这不能回答他的问题。如前所述,他想知道为什么他看不到“1 2 3”,而不是“A B C”。@chepner你显然误解了打印
A B C
而不是1 2 3
的要点,这不会使答案出错。我已经说得很清楚了。他的问题是关于语法错误,而不是如何打印“abc”。在编辑之前,这并没有回答这个问题。@chepner在编辑之前,问题是(现在仍然是)变量不会在子shell中定义,这才是真正的问题。它不需要在子shell中定义。他实际上并没有使用列表的内容,他只是需要长度,在调用子shell之前可以对长度进行评估。通过你的编辑,我实际上已经对你的答案投了更高的票。这并没有回答他的问题。如前所述,他想知道为什么他看不到“1 2 3”,而不是“A B C”。@chepner你显然误解了打印A B C
而不是1 2 3
的要点,这不会使答案出错。我已经说得很清楚了。他的问题是关于语法错误,而不是如何打印“abc”。在编辑之前,这并没有回答这个问题。@chepner在编辑之前,问题是(现在仍然是)变量不会在子shell中定义,这才是真正的问题。它不需要在子shell中定义。他实际上并没有使用列表的内容,他只是需要长度,在调用子shell之前可以对长度进行评估。通过你的编辑,我实际上已经对你的答案投了更高的票。你确定sh
是bash吗?POSIXsh
没有数组。您确定sh
是bash吗?POSIXsh
没有数组。我不确定OP是否有理由将命令传递给子shell,但这肯定更简单。如果在当前shell中,您不需要担心换行符,只需删除“-s”,我不确定OP是否有理由将命令传递给子shell,但这肯定更简单。如果你在当前的shell中,你不需要担心换行,所以你可以删除t