Труба, стандартный ввод и аргументы командной строки в Bash
считаем:
command1 | command2
используется ли вывод command1 в качестве стандартного ввода command2 или в качестве аргументов командной строки для command2?
например,
cat test.sh | grep "hehe"
какова его эквивалентная форма без использования трубы?
пробовал
grep "hehe" $(cat test.sh)
и это кажется неправильным.
4 ответов
grep "hehe" < test.sh
перенаправление ввода-работает только для одного файла, конечно, тогда как cat
работает для любого количества входных файлов.
учитывать указания:
grep "hehe" $(cat test.sh)
grep "hehe" `cat test.sh`
они эквивалентны в этом контексте; гораздо проще использовать '$(cmd)
' нотация во вложенных видах использования, таких как:
x=$(dirname $(dirname $(which gcc)))
x=`dirname \`dirname \\`which gcc\\`\``
(это дает вам базовый каталог, в котором установлен GCC, в случае, если вам интересно.)
на grep
пример, что бывает так, что содержимое test.sh
читается и разбивается на слова, разделенные пробелом, и каждое такое слово предоставляется в качестве аргумента grep
. С grep
обрабатывает слова после "hehe"
(где grep
, конечно, не не см. двойные кавычки - и в этом случае они не нужны; как правило, используйте одинарные кавычки, а не двойные кавычки, особенно вокруг сложных строк, таких как регулярные выражения, которые часто используют метасимволы оболочки)... Как и я. говоря:grep
обрабатывает слова после "hehe"
как имена файлов и пытается открыть каждый файл, как правило, неудачно, потому что файлы не существуют. Вот почему эти обозначения неуместны в данном контексте.
после повторного рассмотрения вопроса, есть еще что можно сказать - это еще не было сказано.
во-первых, многие команды Unix предназначены для работы в качестве "фильтров"; они читают ввод из некоторых файлов, преобразуют его каким-то образом и пишут результат на стандартный выход. Такие команды предназначены для использования в командных конвейерах. Примеры включают:
- кошки
- grep
- трофф и родственники
- на awk (с оговорками)
- sed
- вроде
все эти фильтры имеют одинаковое общее поведение: они принимают параметры командной строки для управления своим поведением, а затем либо читают файлы, указанные в качестве аргументов командной строки или, если таких аргументов нет, они читают свой стандартный ввод. Некоторые (как sort
) может иметь опции для управления, где их выход идет вместо стандартного выхода, но это относительно редко.
есть несколько чистых фильтров - tr
одно такое-что строго прочитайте стандартный входной сигнал и напишите к стандартному выходу.
другие команды имеют различное поведение. Eric Raymond предоставляет таксономию для типов команд в "искусство UNIX Программирование".
некоторые команды генерируют списки имен файлов на стандартном выходе-две классики ls
и find
.
иногда требуется применить выходные данные генератора имен файлов в качестве аргументов командной строки для фильтра. Есть программа, которая делает это автоматически - это xargs
.
классически, можно использовать:
find . -name '*.[chyl]' | xargs grep -n magic_name /dev/null
это создаст полный список файлов с расширениями'.c
', '.h
','.y
' и '.l
' (источник C, заголовки, файлы Yacc и Lex). Как список читается xargs
, он будет создавать командные строки с grep -n magic_name /dev/null
в начале и каждое слово (разделенных пробелом) в качестве аргумента.
в старые времена имена файлов Unix не включали пробелы. Под влиянием Mac и Windows, такие пространства теперь являются общим местом. Версии GNU find
и xargs
дополнительные параметры, чтобы справиться с этим проблема:
find . -name '*.[chyl]' -print0 | xargs -0 grep -n magic_name /dev/null
в '-print0
' опция означает "печать имен файлов, завершенных нулем' \0 '"(потому что единственными символами, которые не могут отображаться в (простом) имени файла, являются " / "и NUL, и, очевидно," / " может отображаться в именах путей). Соответствующее "-0
говорит xargs
искать имена, завершенные нулем, вместо имен, разделенных пробелом.
другой формой перенаправления является подстановка процессов.
grep "hehe" <(cat test.sh)
эквивалентно:
grep "hehe" test.sh
которые оба смотрят на содержимое .
в то время как, как было отмечено, эта команда:
grep "hehe" $(cat test.sh)
ищет файлы в test.sh
и использует их в качестве аргументов grep
. Так что если test.sh
состоит из:
scriptone
scripttwo
затем grep
собирается искать "хе-хе" в содержание каждого из этих файлов.
Он используется как stdin.
попробуй:
grep "hehe" - $(cat test.sh)
это может быть неправильно; я не могу проверить это на этом компьютере. Если вы делаете это без канала, как вы пытались, grep обрабатывает последний аргумент как имя файла, т. е. ищет файл с именем [contents of test.sh]. Если вы передадите его A - (или не поставите последний аргумент), вы скажете ему использовать stdin в качестве файла.
вы также можете просто передать grep файл для сканирования:
grep "hehe" test.sh
...но ты, кажется, спрашиваешь. более обобщенный вопрос bash, а не вопрос использования grep, так что это, вероятно, не слишком полезно.
что такое эквивалент канала bash с использованием аргументов командной строки?
каналы и аргументы командной строки-это разные формы ввода, которые не являются взаимозаменяемыми. Если программа позволяет вам иметь эквивалентные формы обоих, это выбор только этой программы. (В исходном коде аргументы командной строки отображаются в виде текста переменной, а каналы - в виде открытых файлов, включая stdin и stdout. Синтаксис перенаправления ввода-вывода Bash, как используется здесь lateron, технически делает не принадлежат аргументам командной строки, даже если они написаны рядом с ними в командной строке ...)
но давайте будем педантичными, а также ответим на это:
что такое эквивалент трубы bash без использования символа трубы bash?
ответ: cat test.sh | grep "hehe"
эквивалентно
grep "hehe" < <(cat test.sh)
объяснение:
- каналы перенаправляют stdout одной команды на stdin другой. Установить источник stdin, мы можем использовать перенаправление ввода (
< …
) вместо использования этого символа. - однако, просто используя перенаправление ввода (
grep "hehe" < test.sh
) не эквивалентен трубам, потому что он использует в качестве источника для stdin, в то время как трубы используют вывод команды (cat test.sh
). Таким образом, кроме того, мы добавляем процесс substitution<(…)
заменить ввод из файла на ввод из команды. -
конечно, пример сбивает с толку, потому что два варианта имеют одинаковые эффекты:
grep "hehe" < test.sh grep "hehe" < <(cat test.sh)
но технически ввод из файла по-прежнему отличается от ввода из вывода команды, которая получает свой ввод из файла.
источник: Advanced Bash Scripting Manual, раздел о подстановке процессов (начните читать "некоторые другие обычаи").