Почему «echo foo | read a; echo $ a» не работает должным образом? - PullRequest
7 голосов
/ 17 декабря 2008

Я мог бы повторить проблему с различными оболочками в FreeBSD, GNU / Linux и Solaris. Это заставляло меня царапать голову более часа, поэтому я решил опубликовать вопрос здесь.

Ответы [ 8 ]

14 голосов
/ 17 декабря 2008

Благодаря трубопроводу read выполнен в своей собственной оболочке.

echo foo | while read a; do echo $a; done

будет делать то, что вы ожидаете.

6 голосов
/ 17 декабря 2008

альтернатива:

echo foo | (read a ; echo $a)

Edit:

Если вам нужен $ a за пределами подоболочки, вам нужно отменить команды:

read a < <(echo foo); echo $a

таким образом чтение выполняется в текущем процессе

3 голосов
/ 17 декабря 2008

Просто к вашему сведению; в кш он работает как положено; См. Также http://kornshell.com/doc/faq.html, Раздел III (вопросы программирования оболочки), Q13:

Q13.    What is $bar after, echo foo | read bar?
A13.    The is foo.  ksh runs the last component of a pipeline
        in the current process.  Some shells run it as a subshell
        as if you had invoked it as  echo foo | (read bar).
3 голосов
/ 17 декабря 2008

Я не думаю, что это уже было дано:

a=`echo foo`
echo $a
1 голос
/ 27 марта 2012

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

zsh и более новые версии оболочки Korn (по крайней мере, начиная с 93 года, но, возможно, даже до ksh '88) создадут подпроцесс на другой стороне канала (запись в него). ). Таким образом, они будут работать так, как задумал автор этого вопроса. («Как и ожидалось», конечно, очень субъективно. Понимание природы канала должно привести к тому, что он будет вести себя в зависимости от реализации).

Я не знаю, существует ли какое-либо конкретное положение в Posix, Spec 1170 или SuS или любом другом опубликованном стандарте, который требует одну или другую семантику. Однако на практике ясно, что вы не должны зависеть от поведения; хотя вы можете легко проверить это в своих скриптах.

0 голосов
/ 17 декабря 2008

Я предложил решение, которое не скрывает значения переменных в подоболочке и может работать с несколькими значениями.

set `echo foo bar`
A=$1
B=$2
0 голосов
/ 17 декабря 2008

Согласно Кернигану и Пайку Среда программирования Unix (стр. 159) "ни одна из встроенных команд оболочки (в отличие от примитивов потока управления, например, for) не может быть перенаправлена ​​с помощью> и <"и" это может быть описано как ошибка в оболочке ". Это, кажется, объясняет а) почему код типа </p>

ls *.c |
while read file
do
   echo $a
done

неизменно работает без проблем, и б) несоответствие, что перенаправление из файла работает.

0 голосов
/ 17 декабря 2008

чтение ожидает ввода в новой строке

while read a; do echo $a; done
foo
bar
^D

более или менее то, что вы хотели

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...