Использование "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 предназначен для использования как с петлей, так и без нее.

Другие вопросы по тегам