在bash中循环连续两个元组会产生错误的输出

Lil*_*ane 2 bash for-loop

这里找到解决方案后,我试图在bash中实现一个元组循环:

NUMBERS='1,2,3 4,5,6 7,8,9'

for TOUPLE in $NUMBERS;
do IFS=',';
    set -- $TOUPLE
    echo \($1, $2, $3\)
done

echo ''

for TRIPLE in $NUMBERS;
do IFS=',';
    set -- $TRIPLE
    echo \($1, $2, $3\)
done
Run Code Online (Sandbox Code Playgroud)

这些应该基本上是相同的循环,并且它们应该打印相同的输出.但是,当我执行脚本时,我得到以下输出:

(1, 2, 3)
(4, 5, 6)
(7, 8, 9)

(1, , )
(2, , )
(3 4, , )
(5, , )
(6 7, , )
(8, , )
(9, , )
Run Code Online (Sandbox Code Playgroud)

为什么第二个循环的行为与第一个循环不同?

Joh*_*ica 5

第一个循环具有for TOUPLE in $NUMBERS默认值$IFS- 数字在空白处分割.在循环内部,你会改变$IFS,这种变化是永久性的.它不仅会影响以下内容set -- $TOUPLE,还会影响脚本的其余部分.

当第二个for TRIPLE in $NUMBERS运行时,更改以$IFS防止$NUMBERS被正确分割.它用逗号分隔而不是空格.哎呀.

如果要将循环彼此隔离,确保它的最简单方法是将它们包装在括号中,以便它们在子shell中执行.子壳中的变量赋值不会影响父shell.

(
    for TOUPLE in $NUMBERS; do
        IFS=','
        set -- $TOUPLE
        echo "($1, $2, $3)"
    done
)

echo

(
    for TRIPLE in $NUMBERS; do
        IFS=','
        set -- $TRIPLE
        echo "($1, $2, $3)"
    done
)
Run Code Online (Sandbox Code Playgroud)

如果你切换set到a,read你可以$IFS暂时改变reads 的持续时间,并完全避免这种混乱.

for TUPLE in $NUMBERS; do
    IFS=',' read a b c <<< "$TUPLE"
    echo "($a, $b, $c)"
done
Run Code Online (Sandbox Code Playgroud)

我会更进一步,避免循环遍历字符串变量.数组更适合,不涉及任何字符串拆分.远离不带引号的变量扩展是一个好习惯.

tuples=(1,2,3 4,5,6 7,8,9)
for tuple in "${tuples[@]}"; do
    IFS=',' read a b c <<< "$tuple"
    echo "($a, $b, $c)"
done
Run Code Online (Sandbox Code Playgroud)