Bash Coproc и оставшийся вывод Coproc - PullRequest
10 голосов
/ 04 октября 2011

Мне нужно прочитать некоторые данные конфигурации в переменные среды в скрипте bash.

«Очевидный» (но неверный) шаблон:

egrep "pattern" config-file.cfg | read VAR1 VAR2 VAR3 etc...

Это не удается, потому что read запускается в подоболочке и поэтому не может устанавливать переменные в вызывающей оболочке.Таким образом, я придумал это как альтернативу

coproc egrep "pattern" config-file.cfg
read -u ${COPROC[0]} VAR1 VAR2 VAR3 etc...

, которая отлично работает.

Чтобы проверить, что происходит, если сопроцесс возвращает более одной строки, я попробовал это:*

где config-file.cfg содержит три строки.

$ cat config-file.cfg
LINE1 A1 B1 C1
LINE2 A2 B2 C2
LINE3 A3 B3 C3

Я ожидал, что это обработает первую строку в файле, после чего появится какое-то сообщение об ошибке «сломанная труба».В то время как обработал первую строку, сообщения об ошибке не было и сопроцесс не был запущен.

Поэтому я попытался в скрипте следующее:

$ cat test.sh
coproc cat config-file.cfg
read -u ${COPROC[0]} VAR1 VAR2 VAR3 VAR4
echo $VAR1 $VAR2 $VAR3 $VAR4
wait
echo $?

Выполнение:

$ bash -x test.sh
+ read -u 63 VAR1 VAR2 VAR3 VAR4
+ cat config-file.cfg
LINE1 A1 B1 C1
+ wait
+ echo 0
0

Куда делись оставшиеся две строки?Я бы ожидал, что либо «сломанная труба», либо wait зависнет, поскольку нечего было читать оставшиеся строки, но, как вы можете видеть, код возврата был равен нулю.

Ответы [ 3 ]

6 голосов
/ 05 октября 2011

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

read VAR1 VAR2 VAR3 < <(egrep "pattern" config-file.cfg)

"Если используется форма <(список),файл, переданный в качестве аргумента, должен быть прочитан, чтобы получить вывод списка "- о каком" файле, переданном в качестве набора ", они говорят? </p>

Это тоже довольно загадочно для меня.Глава о замене процессов в Advanced Bash-scripting Guide содержит более подробное объяснение.

На мой взгляд, при использовании синтаксиса <(cmd) вывод cmdстановится доступным через именованный канал (или временный файл), а синтаксис заменяется именем файла канала / файла.Таким образом, для приведенного выше примера это будет эквивалентно:

read VAR1 VAR2 VAR3 < /dev/fd/63

, где /dev/fd/63 - это именованный канал, подключенный к стандартному выводу cmd.

2 голосов
/ 04 октября 2011

Если я правильно понимаю ваш вопрос (и надеюсь, что я не излагаю очевидное), read читает по одной строке за раз, как в:

$ read a b c < config-file.cfg && echo $?
0

или:

$ printf '%s\n%s\n' one two | { read; echo "$REPLY";}
one

$ echo ${PIPESTATUS[@]}
0 0

Чтобы прочитать все входные данные, вам понадобится цикл:

$ coproc cat config-file.cfg
[1] 3460

$ while read -u ${COPROC[0]} VAR1 VAR2 VAR3; do echo $VAR1 $VAR2 $VAR3; done
LINE1 A1 B1 C1
LINE2 A2 B2 C2
LINE3 A3 B3 C3
[1]+  Done                    coproc COPROC cat config-file.cfg

Просто добавьте, что это объясняется в FAQ .

1 голос
/ 09 марта 2019

Что происходит, как только завершается подоболочка, родительская оболочка очищает и закрывает FD.Тебе повезло, что ты даже прочитал первую строку!

Попробуйте это в интерактивной оболочке:

$ coproc ECHO { echo foo; echo bar; }
[2] 16472
[2]+  Done                    coproc ECHO { echo foo; echo bar; }
$ read -u ${ECHO[0]}; echo $REPLY
bash: read: -u: option requires an argument
read: usage: read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]

Она даже уничтожает переменную среды.

Теперьпопробуйте это:

$ coproc ECHO { echo foo; echo bar; sleep 30; }
[2] 16485
$ read -u ${ECHO[0]}; echo $REPLY
foo
$ read -u ${ECHO[0]}; echo $REPLY
bar
$ read -u ${ECHO[0]}; echo $REPLY # blocks until the 30 seconds are up

[2]+  Done                    coproc ECHO { echo foo; echo bar; sleep 30; }

Что касается решения вопроса, стоящего за вопросом: да, перенаправление и замена процесса - лучший выбор для данного конкретного примера.

...