我有一個像這樣的字串:
"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"
我希望能夠像這樣分割它:
aString that may haveSpaces IN IT
bar
foo
bamboo
bam boo
我怎麼做? (最好使用單線)
答案1
當我看到 David Postill 的回答時,我想「一定有一個更簡單的解決方案」。經過一些實驗,我發現了以下作品:-
string='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"'
echo $string
eval 'for word in '$string'; do echo $word; done'
這是有效的,因為在執行結果行(即內聯答案)之前eval
擴展了該行(刪除引號並擴展):string
for word in "aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"; do echo $word; done
擴展到同一行的另一個選擇是:
eval "for word in $string; do echo \$word; done"
這裡string
在雙引號內展開,但必須$
轉義,以便word
在執行該行之前不展開(在其他形式中使用單引號具有相同的效果)。結果是:-
[~/]$ string='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"'
[~/]$ echo $string
"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"
[~/]$ eval 'for word in '$string'; do echo $word; done'
aString that may haveSpaces IN IT
bar
foo
bamboo
bam boo
[~/]$ eval "for word in $string; do echo \$word; done"
aString that may haveSpaces IN IT
bar
foo
bamboo
bam boo
答案2
最簡單的解決方案是使用引號的參數建立數組,如果您願意,可以循環遍歷該數組或直接傳遞給命令。
eval "array=($string)"
for arg in "${array[@]}"; do echo "$arg"; done
ps 如果您找到更簡單的方法,請評論eval
。
編輯:
在@Hubbitus 的回答的基礎上,我們有了一個經過完全清理和正確引用的版本。注意:這有點過分了,實際上會在大多數標點符號之前的雙引號或單引號部分中留下額外的反斜杠,但不會受到攻擊。
declare -a "array=($( echo "$string" | sed 's/[][`~!@#$%^&*():;<>.,?/\|{}=+-]/\\&/g' ))"
我將其留給有興趣的讀者進行他們認為合適的修改http://ideone.com/FUTHhj
答案3
看起來 xargs 可以做得很好:
$ a='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"'
$ printf "%s" "$a" | xargs -n 1 printf "%s\n"
aString that may haveSpaces IN IT
bar
foo
bamboo
bam boo
答案4
您可以使用declare
而不是執行此操作eval
,例如:
代替:
string='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo"'
echo "Initial string: $string"
eval 'for word in '$string'; do echo $word; done'
做:
declare -a "array=($string)"
for item in "${array[@]}"; do echo "[$item]"; done
但請注意,如果輸入來自用戶,也不會安全多少!
因此,如果您嘗試使用以下字串:
string='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo" `hostname`'
你會得到hostname
評估(當然可能會有類似的東西rm -rf /
)!
非常非常簡單的嘗試來保護它,只需替換像 backtrick ` 和 $ 這樣的字元:
string='"aString that may haveSpaces IN IT" bar foo "bamboo" "bam boo" `hostname`'
declare -a "array=( $(echo $string | tr '`$<>' '????') )"
for item in "${array[@]}"; do echo "[$item]"; done
現在你得到如下輸出:
[aString that may haveSpaces IN IT]
[bar]
[foo]
[bamboo]
[bam boo]
[?hostname?]
有關方法和優缺點的更多詳細信息,您可能會在這個好答案中找到:https://stackoverflow.com/questions/17529220/why-should-eval-be-avoided-in-bash-and-what-should-i-use-instead/17529221#17529221
但仍然留下了攻擊的向量。 我非常希望在 bash 方法中使用像雙引號 (") 這樣的字串引用,但不解釋內容。