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

  • KSH - если / then / else против двойных усилителей (&&) и двойных труб (||)
  • Код выхода подзаголовка влияет на регистрацию
  • Что такое curl-эквивалент этой команды wget?
  • Создание сценария Unix для лучшего сна
  • Неинтерактивный скрипт, выполняющийся поверх ssh, прерывается, поскольку apt-get заканчивается
  • Изменение пустой строковой переменной внутри оператора switch в функции bash
  • Как получить имя папки с помощью шаблона и проверить его уникальность
  • Ошибка "dircolors: нет переменной окружения SHELL, и параметр типа оболочки не указан"
  • 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.

    Interesting Posts

    Видя странные вопросительные знаки в оболочке bash

    Храните домашнюю папку с OpenSuse 12 до Leap

    Создайте нового пользователя без подсказки с chpasswd

    Как назначить DHCP-адрес клиенту DHCP с помощью dhcpd?

    Могу ли я откатиться от обновления apt-get, если что-то пойдет не так?

    Как принудительно выполнить аутентификацию в exim перед отправкой?

    Чрезмерные сообщения Samba в журналах, как посредничать?

    Получать «файл» по своему запросу?

    Присвоение или привязка пользователя Redhat к использованию определенного идентификатора VLAN

    Как запустить chrome из окна терминала после deb isntallation?

    Как бы я попросил, чтобы будущая версия squashfs включала функции затенения?

    Почему моя команда xmodmap не запускается при запуске / входе?

    RHEL6 Работа в режиме бездействия

    Выполнить команду для нескольких файлов, соответствующих шаблону параллельно

    Не использовать определенные области памяти из-за ошибок

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