Использовать встроенный встроенный bash без цикла while

Я привык к встроенной функции read bash во время циклов, например:

 echo "0 1 1 1 1 2 2 3" |\ while read AB; do echo $A + $B | bc; done 

Я работал над некоторым проектом make , и стало разумным разделить файлы и сохранить промежуточные результаты. Как следствие, я часто заканчиваю измельчение отдельных строк в переменных. Хотя следующий пример работает очень хорошо,

 head -n1 somefile | while read ABCDE FOO; do [... use vars here ...]; done 

это глупо, потому что цикл while никогда не будет запускаться более одного раза. Но без этого while ,

 head -n1 somefile | read ABCDE FOO; [... use vars here ...] 

Когда я их использую, переменные чтения всегда пусты. Я никогда не замечал этого поведения read , потому что обычно я использовал бы циклы для обработки многих похожих строк. Как я могу использовать встроенное read bash без цикла while? Или есть другой (или даже лучший) способ прочитать одну строку в несколько (!) Переменных?

Вывод

Ответы учат нас, это проблема обзора. Заявление

  cmd0; cmd1; cmd2 | cmd3; cmd4 

интерпретируется так, что команды cmd0 , cmd1 и cmd4 выполняются в той же области действия, тогда как команды cmd2 и cmd3 имеют свою собственную подоболочку и, следовательно, разные области. Исходная оболочка является родителем обеих подоболочек.

  • Переименовать скрипт bash - false нет такой ошибки файла или каталога
  • Как запустить сценарий оболочки из любого места
  • Команда cat не работает внутри сценария оболочки
  • awk: разобрать и записать в другой файл
  • Подготовьте ответы на вопросы команды
  • Shell Script для переименования текущего рабочего каталога с заданным именем
  • Вырезать письмо из каждой строки файла
  • Couting всех символов с помощью класса символов BASH
  • 3 Solutions collect form web for “Использовать встроенный встроенный bash без цикла while”

    Это потому, что часть, в которой вы используете vars, представляет собой новый набор команд. Используйте это вместо этого:

     head somefile | { read ABCDE FOO; echo $A $B $C $D $E $FOO; } 

    Обратите внимание, что в этом синтаксисе должно быть пробел после { и a ; (точка с запятой) перед } . Также -n1 не требуется; Только чтение читает первую строку.

    Для лучшего понимания это может вам помочь; он делает то же, что и выше:

     read ABCDE FOO < <(head somefile); echo $A $B $C $D $E $FOO 

    Редактировать:

    Часто говорят, что следующие два утверждения делают то же самое:

     head somefile | read ABCDE FOO read ABCDE FOO < <(head somefile) 

    Ну, не совсем. Первый – это труба от head до встроенного read bash . Один вывод stdout одного процесса в stdin другого процесса.

    Второй оператор – перенаправление и замена процесса. Он обрабатывается самим bash . Он создает FIFO (named pipe, <(...) ), к которому подключается вывод head , и перенаправляет ( < ) его в процесс read .

    Пока это кажется эквивалентным. Но при работе с переменными это может иметь значение. В первом случае переменные не задаются после выполнения. Во втором они доступны в текущей среде.

    В этой ситуации каждая оболочка имеет другое поведение. См. Ссылку, для которой они есть. В bash вы можете обойти это поведение с группировкой команд {} , заменой процесса ( < <() ) или Here string ( <<< ).

    Процитировать из очень полезной статьи wiki.bash-hackers.org :

    Это происходит из-за того, что команды канала выполняются в подоболочках, которые не могут изменять родительскую оболочку. В результате переменные родительской оболочки не изменяются (см. Статью: Bash и дерево процессов ).

    Поскольку ответ был предоставлен несколько раз, альтернативный способ (с использованием не встроенных команд …) заключается в следующем:

     $ eval `echo 0 1 | awk '{print "A="$1";B="$2}'`;echo $B $A $ 1 0 

    Как вы заметили, проблема заключалась в том, что труба для read запускается в подоболочке.

    Один из ответов – использовать heredoc :

     numbers="01 02" read first second <<INPUT $numbers INPUT echo $first echo $second 

    Этот метод хорош тем, что он будет вести себя одинаково в любой оболочке, подобной POSIX.

    Linux и Unix - лучшая ОС в мире.