Зацикливание двух последовательных кортежей в bash дает неправильный вывод - PullRequest
0 голосов
/ 30 мая 2018

Следующее решение найдено здесь Я пытался реализовать цикл над кортежем в 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 голосов
/ 30 мая 2018

Вы должны "кэшировать" переменную 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
0 голосов
/ 30 мая 2018

Первый цикл имеет 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...