Как передать вывод команды другим командам?

83

Пример:

ls | echoничего не печатает (фактически пустая строка). Я ожидаю, что это напечатает список файлов.

ls | grep 'foo'с другой стороны, работает как положено (печатает файлы с именем 'foo').

В этих ситуациях я делаю что-то вроде: ls | while read OUT; do echo $OUT; doneно это довольно громоздко.

Почему конвейер работает с некоторыми командами, но не с другими? Как я могу обойти эту проблему?

Михай Ротару
источник
2
Что вы ожидаете ls | echoсделать? почему бы просто не бежать ls?
Теомега
12
Я использовал самый простой пример, который иллюстрирует мою точку зрения. Я действительно столкнулся с этой проблемой, когда пытался создать однострочник, который бы отображал объекты git в хранилище объектов и их тип. Итак, я передал ID объекта git cat-file, но он просто не работал. Очевидно, что у echo такое же поведение, поэтому я использовал его в качестве примера.
Михай Ротару
также посмотрите на команду -n для xargs, она говорит, сколько аргументов нужно ввести в подкоманду. `... | xargs -n1 git cat-file`
Рич Хомолка

Ответы:

118

Существует различие между аргументами командной строки и стандартным вводом. Канал соединит стандартный вывод одного процесса со стандартным вводом другого. Так

ls | echo

Подключает стандартный вывод ls к стандартному вводу эха. Хорошо верно? Что ж, echo игнорирует стандартный ввод и выводит свои аргументы командной строки (которых в данном случае нет) в свой собственный стандартный вывод. Выход: вообще ничего.

В этом случае есть несколько решений. Одним из них является использование команды, которая читает stdin и создает дамп в stdout, например, cat.

ls | cat

Будет «работать», в зависимости от вашего определения работы.

Но как насчет общего случая. Что вам действительно нужно, так это преобразовать стандартный вывод одной команды в аргументы командной строки другой. Как уже говорили другие, xargsявляется ли в этом случае каноническим вспомогательным инструментом, считывая аргументы командной строки для команды из своего стандартного ввода и создавая команды для запуска.

ls | xargs echo

Вы также можете преобразовать это, используя команду замещения $()

echo $(ls)

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

Оба эти инструмента являются довольно ядром сценариев оболочки, вы должны изучить оба.

Для полноты, как вы указали в вопросе, другой базовый способ преобразования stdin в аргументы командной строки - встроенная readкоманда оболочки . Он преобразует «слова» (слова, как определено в IFSпеременной) во временную переменную, которую вы можете использовать при любом запуске команды.

Рич Гомолка
источник
1
Очень полезный информативный ответ, спасибо! В настоящее время я изучаю bash, и раньше я видел и xargs, и нотацию $ (*), но не обращал на них особого внимания. Теперь я знаю, насколько они важны, и обязательно буду их изучать.
Михай Ротару
1
xargs мог быть тем, что искал OP.
Iktys
19

ls | echoпечатает только пустую строку, потому что не echoчитает ввод; последняя команда конвейера на самом деле echoвыводит только пустую строку.

В общем:

a | b

удостоверяется, что выходные данные aстановятся входными данными b. Я предлагаю вам прочитать Pipelinesраздел man bash.


Если вы действительно хотите использовать lsи echoвместе вот некоторые (довольно бесполезные) примеры:

ls | xargs -L 1 echo
echo `ls`
for i in `ls` ; do echo $i ; done
Кир
источник
11

Если вы хотите echoв lsкомандной попытке:

ls | xargs echo

Это вызовет echoс выводом ls.

Натан Феллман
источник
3
Или, ls | xargs -I {} echo {}если вы хотите, чтобы он вызывался для каждой строки индивидуально
Алексей Абдугафаров
3

Почему бы просто не использовать:

echo `ls`

Или намного безопаснее:

echo "`ls -lrt`"
Urbwzrd
источник
4
Или даже просто echo *.
Казарк