Использование "while read..." в скрипте Linux
Может кто-нибудь объяснить, как работает следующий код?
echo '1 2 3 4 5 6' | while read a b c
do
echo $c $b $a
done
В частности, я хотел бы знать, почему вывод этого цикла 3 4 5 6 2 1
, вместо 3 2 1
а также 6 5 4
на две отдельные строки? Я не могу обернуться вокруг этого...
2 ответа
read
читает всю строку из стандартного ввода, разбивает строку на поля и присваивает эти поля указанным переменным. Если частей больше, чем переменных, оставшиеся части присваиваются последней переменной.
В твоем случае $a
назначен 1
, $b
назначен 2
а также $c
остальные 3 4 5 6
,
Переписав цикл таким образом, вы узнаете, что происходит:
echo '1 2 3 4 5 6' | while read a b c
do
echo '(iteration beginning)' a="$a" b="$b" c="$c" '(iteration ending)'
done
Это дает в качестве вывода:
(iteration beginning) a=1 b=2 c=3 4 5 6 (iteration ending)
Сначала обратите внимание, что выполняется только одна команда echo. Если бы он запускался более одного раза, вы бы, среди прочего, увидели (iteration beginning)
а также (iteration ending)
подстроки печатаются более одного раза.
Это означает, что имея while
цикл здесь на самом деле ничего не делает. read
Встроенная функция считывает разделенный пробелами текст 1 в каждую указанную переменную. Дополнительный ввод добавляется в конец последней указанной переменной. 2 Таким образом, переменные a
а также b
взять на себя значения 1
а также 2
соответственно пока c
принимает значение 3 4 5 6
,
Когда условие цикла (while read a b c
) оценивается во второй раз, больше нет входных данных из канала (мы передали ему только одну строку текста), поэтому read
Команда оценивается как ложь вместо истины, и цикл останавливается (перед выполнением тела во второй раз).
1: чтобы быть техническим и конкретным, read
Встроенный, когда передаются имена переменных в качестве аргументов, считывает ввод, разделяя его на отдельные "слова", когда встречает пробел IFS (см. также этот вопрос и эту статью).
2: read
Вначале поведение заклинивания любых дополнительных полей ввода в последней указанной переменной неинтуитивно для многих сценариев. Это становится легче понять, если учесть, что, как отвечает Флориан Дайш, read
всегда будет (пытаться) прочитать всю строку - и это read
предназначен для использования как с петлей, так и без нее.