2013-03-07 96 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