2013-03-07 95 views
2

我在做什么错了?在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' 
+1

你确定'sh'是bash的? POSIX'sh'没有数组。 – jordanm 2013-03-07 15:19:05

回答

2

在你的原代码,你传递给/bin/sh双引号的字符串被shell调用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,因为POSIX sh不支持数组,正如jordanm所指出的那样。

+0

我们的答案以不同的方式解决了这个问题。我让'seq'命令在当前shell中计算,以便将序列'1 2 3'(不带换行符)传递给子shell。您将'list'的定义移动到子shell中并在其中执行操作。他原来的语法错误是由于他传递给'/ bin/[ba] sh'的字符串包含嵌入的换行符,导致'for'循环被错误地解析。用'set -x'运行他的原始代码来查看问题。 – chepner 2013-03-07 15:34:25

+0

它为我工作。 – 2013-03-07 15:35:11

0

阵列时产卵子外壳list不会被定义,因此它不会有任何长度制作:视为

for i in `seq 1 ${#list[@]}` 

for i in seq 1 0 

参见:

$ sh -c 'echo ${#list[@]}' 
0 

seq 1 0不产生输出,因此看不到任何结果。

要么设置list并在当前shell打印出的每个值:在子shell

$ list=("A" "B" "C") 

$ for i in `seq 1 ${#list[@]}`;do echo $i;done 
1 
2 
3 

或定义list

$ sh -c 'list=("A" "B" "C");for i in `seq 1 ${#list[@]}`;do echo $i;done' 
1 
2 
3 
+0

这不回答他的问题。如上所述,他想知道他为什么看不到'1 2 3',而不是'A B C'。 – chepner 2013-03-07 15:07:48

+1

@chepner你明显误解了印刷“A B C”而不是“1 2 3”这一点并不会使答案错误。我已经明确表示了。 – 2013-03-07 15:21:05

+1

他的问题是关于获取语法错误,而不是如何打印'A B C'。在编辑之前,这并没有回答这个问题。 – chepner 2013-03-07 15:23:40

2

@chepner给你正确的答案。

顺便说一句,你还可以缩短了命令像这样(没有进一步的外壳参与)

unset list 
list=("A" "B" "C") 
for i in `seq 1 ${#list[@]}` ; do echo $i ; done 
+0

我不确定OP是否有很好的理由将命令传递给子shell,但这绝对简单。 – chepner 2013-03-07 15:24:35

+1

如果你在当前的shell中,你不需要担心换行符,所以只需放下'-s \' – 2013-03-07 15:39:41

+0

@sudo_O这是真的! – 2013-03-07 15:40:41