在找到解决方案后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, , )
为什么第二个循环的行为与第一个循环不同?
答案 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