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

时间:2018-05-30 13:25:56

标签: bash for-loop

在找到解决方案后here我试图在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

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

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

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

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

2 个答案:

答案 0 :(得分:5)

第一个循环有for TOUPLE in $NUMBERS,默认为$IFS - 数字在空白处拆分。在循环内部,您可以更改$IFS,此更改是永久性的。它不仅会影响以下set -- $TOUPLE,还会影响脚本的其余部分。

当第二个for TRIPLE in $NUMBERS运行时,对$IFS的更改会使$NUMBERS无法正确拆分。它用逗号分隔而不是空格。糟糕。

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

(
    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
)

如果您将set切换为read,则可以在$IFS期间暂时更改read,并完全避免这种混乱。

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

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

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

答案 1 :(得分:1)

您应该“缓存”IFS变量并在两个循环之间恢复它

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

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

echo ''

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