Использование труб в спинах - PullRequest
2 голосов
/ 24 августа 2011

Я пытаюсь запустить команду с конвейером, но получаю ошибки:

echo abc | `echo "grep a | grep b"`
grep: |: No such file or directory
grep: grep: No such file or directory
grep: b: No such file or directory

Что не так с кодом?

Ожидаемые результаты для выполнения следующей команды:

echo abc | grep a | grep b

С результатом

abc

Ответы [ 4 ]

3 голосов
/ 24 августа 2011

Непонятно, что вы пытаетесь сделать, но вот что вы делаете:

echo "grep a | grep b"

выводит строку grep a | grep b.

Это вывод с обратной галочки. Вы используете обратные пометки в положении, когда оболочка хочет команду, поэтому "grep" a '' | ' 'grep' 'b' "используется в качестве командной строки, причем все токены интерпретируются буквально (я добавил одиночные кавычки, чтобы сделать это немного более понятным, надеюсь), поэтому оболочка игнорирует ввод из echo и вместо этого пытается искать регулярное выражение a в именованных файлах. У вас, очевидно, нет файлов с именами «|», «grep» или «b», поэтому вы получаете сообщение об ошибке.

То, что вы можете хотеть, это

echo abc | grep a | grep b

, который ищет «a» в выходных данных «echo», а затем ищет «b» в выходных данных первого grep. Поскольку abc соответствует регулярному выражению a, первое grep завершается успешно, поэтому соответствующая строка печатается; и поскольку оно также соответствует регулярному выражению b, оно печатается также и в конце grep.

Чтобы немного расширить это, попробуйте следующее:

sh$ echo abc; echo bcd; echo xya
abc
bcd
xya

sh$ ( echo abc; echo bcd; echo xya ) | grep a  # print lines matching a
abc
xya

sh$ (echo abc; echo bcd; echo xya ) | grep a | grep b  # print lines matching a and b
abc

Непонятно, почему вы используете backticks; если это не то, чего вы пытаетесь достичь, пожалуйста, объясните более подробно, чего вы хотите достичь.

Если вы хотите найти строки, соответствующие a или b, попробуйте это:

sh$ ( echo abc; echo bcd; ) | grep '[ab]'
2 голосов
/ 25 августа 2011

Объяснение Трипли довольно близко (если не сказать точно то же самое) к тому, что я думаю, происходит.«Clasic Shell Scripting» [Robbins & Beebe], раздел 7.8.1, на самом деле имеет хорошее объяснение гоча, которое связано с моим первоначальным вопросом.

Если вы напишите

listpage="ls | more" 
$listpage

, вы получите похожую проблему, где '|'& 'more' считаются аргументами для ls.Причина в том, что в точке, где подстановка переменных выполняется оболочкой (шаг 5/10), исходный вход уже был разбит на токены (из которых | - один) (шаг 1/10).Так что '|'теряет свое особое значение и рассматривается как аргумент.

Однако, если вы напишите:

eval $listpage

eval заставит оболочку перезапуститься обратно на шаге 1, где '|'персонаж считается специальным токеном.

2 голосов
/ 24 августа 2011

Символ канала является специальным, только если вы позволяете bash-парсеру видеть его. Вы цитировали его, используя "", так что он больше не является особенным, и grep считает, что вы хотите, чтобы он извлек строку a из файлов |, grep и b.

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

Единственный способ снова обработать такого символа как особого - это повторно передать его на совершенно новый вызов интерпретатора оболочки, что и делает решение Роберта Мартина.

0 голосов
/ 24 августа 2011

Эта часть неверна:

$ `echo "grep a | grep b"`

Поскольку обратные тики не понимают канал.Попробуйте эту альтернативу, которая делает то же самое:

$ echo "grep a | grep b" | sh
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...