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 (с оговорками)
- 1041 * СЭД *
- 1043 * рода *
Все эти фильтры имеют одинаковое общее поведение: они используют параметры командной строки для управления своим поведением, а затем либо читают файлы, указанные в качестве аргументов командной строки, либо, если таких аргументов нет, они читают их стандартный ввод. Некоторые (например, sort
) могут иметь параметры для контроля того, куда идет их вывод вместо стандартного, но это относительно редко.
Существует несколько чистых фильтров - один из них tr
- строго читает стандартный ввод и записывает в стандартный вывод.
Другие команды имеют другое поведение. Эрик Рэймонд предоставляет таксономию для типов команд в " Искусство программирования UNIX ".
Некоторые команды генерируют списки имен файлов при стандартном выводе - две классики: ls
и find
.
Иногда вы хотите применить выходные данные генератора имен файлов в качестве аргументов командной строки для фильтра. Есть программа, которая делает это автоматически - это xargs
.
Классически вы бы использовали:
find . -name '*.[chyl]' | xargs grep -n magic_name /dev/null
Это приведет к созданию полного списка файлов с расширениями '.c
', '.h
', '.y
' и '.l
' (C source, заголовки, файлы 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
' означает «печатать имена файлов, оканчивающиеся NUL '\ 0'" (потому что единственными символами, которые не могут появиться в (простом) имени файла, являются '/' и NUL, и, очевидно, ' / 'может появляться в именах путей). Соответствующий '-0
' говорит xargs
искать имена, оканчивающиеся NUL, вместо имен, разделенных пробелом.