2017-05-27 58 views
0

例如:爲什麼`in in`不能直接在bash中拆分字符串?

# case 1 
for i in "a b c"; do echo -n $i| od -b; done 
# case 2 
v="a b c"; for i in $v; do echo -n $i| od -b; done 

輸出:

0000000 141 040 142 040 143 
0000005 
0000000 141 
0000001 
0000000 142 
0000001 
0000000 143 
0000001 

爲什麼for in不能在bash直接拆分字符串?案例1和案例2有什麼區別?

+1

您爲什麼要*想要它?這意味着你不能在不分割它們的情況下遍歷一個字符串數組;那會很糟糕。 –

+0

...說,一般*字符串分裂*是可怕的,寫得很好的程序不會使用它。 –

+0

也就是說,'echo -n'也是*糟糕的 - 請參閱[相關的POSIX規範](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html),它明確建議使用'而不是(請參閱應用使用和理論部分)。 –

回答

2

文字分割是非引用參數擴展(以及未引用的命令擴展)中的一項功能。這不是for循環的功能。

  • 未加引號的變量在for循環中拆分字符串,因爲未引用的變量將字符串(幾乎)分散到任何地方。

  • for循環不直接拆分字符串,因爲它們根本不拆分字符串。這不是循環的責任。

這裏有三個例子,每個例子都有一個文字字符串,一個帶引號的變量和一個不帶引號的變量。您可以看到,沒有特殊情況,所有拆分都是由於未引用參數擴展引起的:

var="a b c" 

command "a b c" "$var" $var 
         ^-- Only thing that splits 

array=("a b c" "$var" $var) 
         ^-- Only thing that splits 

for s in "a b c" "$var" $var 
do ...     ^-- Only thing that splits 
3

如果for循環自動執行字符串分割,這意味着下面的代碼是不可能的:

# this should be (and currently is!) two lines, not four. 
for message in "hello world" "goodbye world"; do 
    echo "$message" 
done 

,或者對於一個稍微現實世界的例子,考慮:

shopt -s nullglob 
echo "Listing length in lines of files with spaces in their names from My Documents" 
for file in "My Documents"/*; do 
    printf '%s\t%s lines\n' "$file" "$(wc -l <"$file")" 
done 
echo "Done" 

。 ..在這種情況下,執行了字符串拆分的for循環會將My視爲單獨的文件名,而不是將文件名保存在一起。


如果你想安全將一個字符串分解成多個元素,使用read -a,不串分裂:

v='a b c' 
read -r -a v_a <<<"$v" 
for i in "${v_a[@]}"; do 
    printf '%s' "$i" | od -b 
done 

這將正常工作,即使輸入值是字符串分割會Munge時間 - - 例如,考慮v='*',其中字符串拆分將用當前目錄中的文件列表替換*字符。

相關問題