Использование «while read…» в скрипте Linux

34

Может кто-нибудь объяснить, как работает следующий код?

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на две отдельные строки? Я не могу обернуться вокруг этого ...

linuxgringo
источник

Ответы:

41

readчитает всю строку из стандартного ввода, разбивает строку на поля и присваивает эти поля указанным переменным. Если частей больше, чем переменных, оставшиеся части присваиваются последней переменной.

В вашем случае $aназначается 1, $bназначается 2и $cостальное 3 4 5 6.

Флориан Диш
источник
Спасибо, Флориан! Теперь это имеет смысл ... Почему-то я думал, что пробелы будут ограничивать чтение каждой переменной, но, видимо, нет. Я ценю вашу помощь!!
linuxgringo
24

Переписав цикл таким образом, вы узнаете, что происходит:

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 : Чтобы быть техничная, встроенной , при передаче имен переменных в качестве аргументов, считывает информацию, разделив его на отдельные «слова» , когда он встречает IFS пробельные (смотри также этот вопрос и в этой статье ).read

2 : readповедение заклинивания любых дополнительных полей ввода в последней указанной переменной, на первый взгляд, неинтуитивно для многих сценариев. Понять это становится легче, если учесть, что, как говорится в ответе Флориана Диша , readон всегда будет (пытаться) прочитать целую строку - и это readпредназначено для использования как с циклом, так и без него.

Элия ​​Каган
источник
Элия, спасибо, что нашли время, чтобы объяснить все детали. Я подозревал, что whileв этом примере это не служило своей обычной цели, но затем readкоманда отбросила меня ... Каким-то образом я интерпретировал это как "пока read a b cне ложь, делай echo ...". Спасибо за объяснение, как это действительно работает. Я вчера натолкнулся на этот код и знал, что он будет беспокоить меня, пока я не разобрался в этом ... lol
linuxgringo
@linuxgringo На самом деле, тело цикла будет выполняться каждый раз , read a b cистинно, и условие цикла ( read a b c) не запускать более чем один раз. Бит только в первый раз оценивается как истина . Во второй раз больше нет входных данных для чтения из канала, поэтому встречается конец файла , в результате чего readвозвращается false . (Подробности см. В последнем разделе выходных данных help read«Состояние выхода», отметив, что в сценариях оболочки ноль означает «истина», а ненулевой - «ложь».) Если вы передадите более одной строки ввода while read ..., тело цикла будет исполняться несколько раз.
Элия ​​Каган,