Как передать выходные данные одной команды нескольким командам?


20

Используя подстановку процесса или группировку и конвейер, можно передать вывод ( stdout ) набор команд в качестве ввода для другой команды.

Пример :

wc < <(echo hi;echo bye)
(echo hi; bye) | wc

Но есть ли обратное?

То есть есть ли способ отправить вывод одной команды в качестве ввода для многих других команд в одной строке ?

Что-то типа :

cat testfile | wc | tail -n 5

( Не воспринимайте трубопроводы буквально ). Здесь я пытаюсь передать выходные данные cat testfileобоим wcиtail -n 5

Другой пример будет:

( чтобы получить последнее слово в предложении )

echo "some random words"| wc -c | cut -f(out put of wc -c) (output of first echo)

Ответы:


21

Быстрый ответ. Вы можете использовать tee >(what_to_do) >(another_thing_to_do)для продолжения выполнения своей команды столько разных вещей, которые вы хотите сделать.

Пример:

Исходный тестовый файл вывода:

:~$ cat testfile.txt 
Device Model:     LITEONIT LCS-256M6S 2.5 7mm 256GB
Serial Number:    TW0XFJWX550854187616

Вывод с teeдобавленными командами:

:~$ cat testfile.txt | tee >(tail -1) >(wc) >(awk '{print $3,$1,$2}')
Device Model:     LITEONIT LCS-256M6S 2.5 7mm 256GB
Serial Number:    TW0XFJWX550854187616
LITEONIT Device Model:
TW0XFJWX550854187616 Serial Number:
      2      10      91
Serial Number:    TW0XFJWX550854187616

Каждая команда в tee - это обычные команды, которые вы используете в командной строке, например, add in >(head -1 | wc)works.

:~$ cat testfile.txt | tee >(tail -1) >(head -1 | wc)  >(awk '{print $3,$1,$2}')
Device Model:     LITEONIT LCS-256M6S 2.5 7mm 256GB
Serial Number:    TW0XFJWX550854187616
      1       7      52
LITEONIT Device Model:
TW0XFJWX550854187616 Serial Number:
Serial Number:    TW0XFJWX550854187616

Или вы можете также захватить последнее слово сказать последнюю строку, используя awkс $NFс wcа так:

:~$ cat testfile.txt | tail -1 | tee >(wc) >(awk '{print $NF}')
Serial Number:    TW0XFJWX550854187616
TW0XFJWX550854187616
      1       3      39

ПРИМЕЧАНИЕ. Добавление |в конец команды pipe может быть отменено с помощью нескольких команд из teeкоманды. У меня есть несколько примеров, которые я тестировал:

Пример 1 (команда Pipe извлекает все последние слова):

:~$ echo "This is just five words" | tee >(wc -l) >(wc -w) >(wc -c) | awk '{print $NF}'
words
24
5
1

Пример 2 (Не показывает вывод команд wc. Команда pipe захватывает 3-е слово.):

:~$ echo "This is just five words" | tee >(wc -l) >(wc -w) >(wc -c) | awk '{print $3}'
just

Пример 3 (Захват 3-го слова в строке эха. Команда Tee.):

:~$ echo "This is just five words" | tee >(wc -l) >(wc -w) >(wc -c) >(awk '{print $3}')
This is just five words
just
24
5
1

Пример 4 (Получение последнего слова в строке эха. Команда Tee.):

:~$ echo "This is just five words" | tee >(wc -l) >(wc -w) >(wc -c) >(awk '{print $NF}')
This is just five words
words
24
5
1

Надеюсь это поможет!


3
Я люблю чай и кофе! '-)
Старейшина Компьютерщик

1
Утверждение о порядке вывода продукции между различными потребителями teeявляется ложным. Причина, по которой вы обычно получаете правильный заказ, заключается в том, что на компьютере с низкой нагрузкой первым запускается первый потребительский процесс. На более загруженной машине первого потребителя можно усыпить, прежде чем он сможет что-либо напечатать.
Матей Дэвид

@MateiDavid Я не могу доказать это иначе, поэтому я просто удалил утверждение. Нет, важная персона.
Терренс

2
Смотри мой ответ. Но, если серьезно, teeпонятия не имеет о потребителях - они создаются тем, bashкто обрабатывает линию. Все, что bashнужно, это скопировать дескрипторы открытого файла. Кроме того, у вас есть несколько потребителей, пишущих в файловые дескрипторы, открытые в одном и том же файле. Ядро позаботится об этом, но, конечно, порядок, в котором они появились в bashкомандной строке, не будет иметь значения.
Матей Дэвид

17

Вам нужно teeразделить поток на части. Пытаться:

cat testfile | tee >(wc -l) >(wc -w) >(wc -c) | tail -n 5

Примечания:

  • Если несколько процессов ( wc, tail) все пишут в стандартный вывод:

    • Вы можете получить искаженный вывод.

    • Нет никакой гарантии в том порядке, в котором они появятся. Чтобы увидеть это, попробуйте sleep 1; wc -wв качестве второго потребителя.

  • teeзаблокирует, если какой-либо из его пунктов назначения не потребляет поток достаточно быстро. Это означает, что получатели будут получать ввод с примерно одинаковой скоростью (по модулю буферизации фиксированного размера). Это не легко исправить, единственная альтернатива - сохранить поток в файл и раздать его потребителям отдельно. Ибо wcи tailэто не проблема.

Для последнего слова проще сделать:

echo "some random words" | awk '{print $NF}'

5

moreutilsПакет предоставляет команду pee(слияние трубы и тройник, что же вы думаете?) , Который делает именно это.

Для первого примера вы бы использовали:

cat testfile | pee wc "tail -n 5"

Второй пример более сложный, потому что вы хотите передать два ввода последней команде. Я бы, вероятно, использовал awkв качестве других ответов.

Ссылка: https://joeyh.name/code/moreutils/

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.