Используйте конвейер команд в качестве аргумента для diff - PullRequest
42 голосов
/ 24 марта 2012

У меня проблемы с этой простой задачей:

cat file | grep -E ^[0-9]+$ > file_grep
diff file file_grep

Проблема в том, что я хочу сделать это без file_grep

Я пробовал:

diff file `cat file | grep -E ^[0-9]+$`

и

diff file "`cat file | grep -E ^[0-9]+$`"

и несколько других комбинаций :-) но я не могу заставить его работать. Я всегда получаю сообщение об ошибке, когда diff получает дополнительный аргумент, который является содержимым файла, отфильтрованного по grep.

Нечто подобное всегда работало для меня, когда я хотел echo выводить команды из скрипта, подобного этому (используя обратные клавиши):

echo `ls`

Спасибо

Ответы [ 5 ]

55 голосов
/ 24 марта 2012

Если вы используете bash:

diff file <(grep -E '^[0-9]+$') file

Последовательность <(COMMAND) расширяется до имени псевдофайла (например, /dev/fd/63), из которого вы можете прочитать выходные данные команды.

Но для этого конкретного случая решение Руаха проще. Он использует тот факт, что - в качестве аргумента для diff заставляет его читать его стандартный ввод. Синтаксис <(COMMAND) становится более полезным, когда оба аргумента diff являются выводом команды, например:

diff <(this_command) <(that_command)
40 голосов
/ 24 марта 2012

Самый простой подход:

grep -E '^[0-9]+$' file | diff file -

Дефис - в качестве имени файла представляет собой специальную запись, которая говорит diff «использовать стандартный ввод»; это задокументировано на справочной странице diff. (Большинство распространенных утилит поддерживают одинаковые обозначения.)

Причина, по которой обратные пометки не работают, заключается в том, что они фиксируют выходные данные команды и передают ее в качестве аргумента . Например, это:

cat `echo file`

эквивалентно этому:

cat file

и это:

diff file "`cat file | grep -E ^[0-9]+$`"

эквивалентно примерно так:

diff file "123
234
456"

То есть фактически он пытается передать 123234345 (плюс новые строки) как имя файла , а не как содержимое файла. Технически, вы могли бы добиться последнего, используя функцию «подстановки процессов» Bash, которая фактически создает своего рода временный файл:

diff file <(cat file | grep -E '^[0-9]+$')

но в вашем случае это не нужно, потому что diff поддерживает -.

9 голосов
/ 24 марта 2012
grep -E '^[0-9]+$' file | diff - file

, где - означает «чтение со стандартного ввода».

6 голосов
/ 24 марта 2012

Попробуйте заменить процесс:

$ diff file <(grep -E "^[0-9]+$" file)

Из справочной страницы bash:

Процесс замены

Подстановка процессов поддерживается в системах, которые поддерживают именованные каналы (FIFO) или метод / dev / fd именование открытых файлов. Он принимает форму <(список) или> (список). Список процессов запускается со своим вводом или выход подключен к FIFO или некоторому файлу в / dev / fd. Имя этого файла передается в качестве аргумента текущая команда как результат расширения. Если используется форма> (список), запись в файл предоставит вход для списка. Если используется форма <(list), файл, переданный в качестве аргумента, должен быть прочитан получить вывод списка. </p>

4 голосов
/ 24 марта 2012

В bash синтаксис:

diff file <(cat file | grep -E ^[0-9]+$)
...