循環中 IFS 分隔的項目

循環中 IFS 分隔的項目

建議使用 IFS 循環逗號分隔的列表,例如這裡。但是,我看到了

sentences="Hello World,Questions"
IFS=, sentences1=($sentences) # if we comment this line then loop is fixed
sentences2=$sentences
for sentence in ${sentences2[@]}; 
do
    for i in $(seq 1 2);
    do
            #This is fine - prints a new word every line
            #echo $sentence

            #This is fine - prints new number every line
            #echo $i

            echo $i $sentence
    done
done

產生

1 
2 Hello World
1
2 Question

代替

1 Hello World
2 Hello World
1 Question 
2 Question

想要的。曾經是一個?

答案1

這裡的主要問題是第二行將IFS=, sentences1=($sentences)IFS 永久設定為“,”;這意味著您在腳本的其餘部分中會遇到奇怪且意外的解析行為。請注意,對於類似 的情況IFS=, read ...,不會發生這種情況,因為 IFS 分配被視為僅適用於命令read;但在 中IFS=, sentences1=($sentences),沒有真正的指令,只有賦值,因此賦值被視為應用於整個 shell。

那麼,讓我們看看腳本的其餘部分發生了什麼。sentences2=$sentences只是複製sentencessentences2,所以for sentence in ${sentences2[@]}有點奇怪。sentences2不是一個數組(只是一個普通的字串),所以該[@]位不執行任何操作,但由於 IFS 仍然是“,”,它會“分詞”成“Hello World”和“Questions”——即你得到正確的結果,但出於錯誤的原因。

(注意:如果它是一個實際的數組,您需要在它周圍加上雙引號,以for sentence in "${sentences2[@]}"防止元素被分詞。)

下一個命令for i in $(seq 1 2)是真正的麻煩開始的地方。seq 1 2列印“1[newline]2[newline]”,該$( )構造會修剪尾隨的換行符,然後“1[newline]2”進行分詞 - 但由於那裡沒有逗號,因此它被視為一個單字(這恰好發生在包含換行符)。因此,內部循環僅運行一次,i設定為“1[newline]2”。

下一行echo $i $sentence列印“1[newline]2”,後面跟著一個空格,然後是 的內容sentence。在第一次迭代中,sentence設定為“Hello World”,列印:

1 
2 Hello World

……中間的換行符使得這看起來像是正在列印的兩件事,但它實際上只是echo碰巧包含換行符的一個。

因此,有兩個重要建議:首先,當您變更 IFS 時,請稍後再將其變更回來。其次,始終使用雙引號變數引用以避免意外的分詞(和通配符擴展)。這是我從腳本中得到的內容:

#!/bin/bash

sentences="Hello World,Questions"

saveIFS="$IFS"
IFS=, sentences1=($sentences)
IFS="$saveIFS"  # Set IFS back to normal!

for sentence in "${sentences1[@]}"; do  # Note double-quotes, and sentences1 is 
an actual array  
    for i in $(seq 1 2); do  # No double-quotes, we *want* seq's output to be spli
t
        echo "$i" "$sentence"  # Double-quotes for safety
    done
done

答案2

我不知道是什麼原因,但 irc://freenode/bash 提供了解決方案

while IFS=, read -ra items; do
    for item in "${items[@]}"; do
        for i in {1..3}; do
            printf '%d %s\n' "$i" "$item"
        done
    done
done <<< "Hello World,Questions,Answers"

列印正確。

相關內容