Как передать стандартный вывод, сохраняя его на экране? (а не в выходной файл)

Я хотел бы передать стандартный вывод программы по конвейеру, сохранив его на экране.

На простом примере (echo используйте здесь только для иллюстрации):

$ echo 'ee' | foo
ee ‹- результат, который я хотел бы увидеть

Я знаю, что tee может копировать стандартный вывод в файл, но мне это не нужно.
$ echo 'ee' | tee output.txt | foo

Я пробовал
$ echo 'ee' | tee /dev/stdout | foo, но это не работает, так как выход тройника на /dev/stdout передается по трубопроводу на foo


person gentooboontoo    schedule 15.04.2011    source источник
comment
Обратите внимание, что echo 'ee' | tee /dev/stderr работает, поэтому, если ваше требование на экране удовлетворяется и stderr, это подойдет.   -  person nh2    schedule 27.03.2016


Ответы (5)


Вот решение, которое работает в любой реализации Unix / Linux, при условии, что оно следует стандарту POSIX. Он работает и в некоторых средах, отличных от Unix, например cygwin.

echo 'ee' | tee /dev/tty | foo

Ссылка: The Open Group Base Specifications Issue 7 IEEE Std 1003.1, 2013 Edition, §10.1:

/ dev / tty

Связан с группой процессов этого процесса, если есть. Это полезно для программ или процедур оболочки, которые хотят быть уверены в том, что они пишут сообщения или читают данные с терминала, независимо от того, как был перенаправлен вывод. Его также можно использовать для приложений, которые требуют имя файла для вывода, когда желателен типизированный вывод и утомительно выяснять, какой терминал в настоящее время используется. В каждом процессе синоним управляющего терминала

Сообщается, что в некоторых средах, таких как Google Colab, /dev/tty не реализован, хотя команда tty, возвращающая пригодное к употреблению устройство. Вот обходной путь:

tty=$(tty)
echo 'ee' | tee $tty | foo

или с древней раковиной Борна:

tty=`tty`
echo 'ee' | tee $tty | foo
person jlliagre    schedule 15.04.2011
comment
это будет работать в интерактивном режиме, для процессов, работающих с tty (например, cron job), вы хотите использовать один из трюков, упомянутых в других ответах. - person Asya Kamsky; 26.11.2014
comment
@AsyaKamsky Речь идет о процессах, которые выводятся на экран. Это исключает задания cron, которые изначально отсоединяются от любого экрана. - person jlliagre; 26.11.2014
comment
@static_rtti Почему вы год за годом игнорируете мои ответы на ваш комментарий? - person jlliagre; 31.12.2015
comment
На моем компьютере с FreeBSD 9.1 нет / dev / tty. Есть какие-нибудь подсказки для меня? (Мне не удалось решить эту проблему с помощью руководства, freebsd.org/doc/handbook /term.html). Ответ на замену процесса работает, но мне любопытно, можно ли заставить его работать. - person Paul Bissex; 25.01.2016
comment
@PaulBissex /dev/tty - обязательное устройство Unix. Вы сидите в тюрьме BSD? - person jlliagre; 28.01.2016
comment
@jillagre Да, это VPS. - person Paul Bissex; 28.01.2016
comment
@PaulBissex Это либо ошибка реализации, либо ошибка конфигурации. / Dev смонтирован? Что показывает ls -l / dev / tty / dev / tty * / dev? См. lists.freebsd.org/pipermail/freebsd-bugs/2012 -Ноябрь / forum.freebsd.org/threads/ - person jlliagre; 29.01.2016
comment
@jlliagre - / dev смонтирован, да. Он содержит dpaste.com/06CME89. Нет / dev / tty. Насколько мне известно, это стандартная установка тюрьмы на сайте johncompanies.com (мой хост). - person Paul Bissex; 30.01.2016
comment
И вы можете каскадировать tee следующим образом: cat some.log | tee /dev/tty | tee -a other.log | grep -i 'foo' >> foo.log на 1) передать все в консоль, 2) добавить все это в другой файл, 3) получить строки foo в другой файл. - person Jesse Chisholm; 09.03.2017
comment
В Google Colab нет /dev/tty, но результат tty можно использовать. - person Tom Hale; 12.01.2019
comment
@TomHale Спасибо, ответ обновлен, чтобы включить этот случай. - person jlliagre; 13.01.2019
comment
Разве в команде colab не должно быть $(/usr/bin/tty) вместо $(/dev/tty)? - person SpoonMeiser; 14.01.2019
comment
@SpoonMeiser Конечно, есть. Фиксированный. Я оставил команду без пути, поскольку tty не обязательно находится в /usr/bin. - person jlliagre; 14.01.2019
comment
Когда tty находится в канале, он возвращает "not a tty\n", поскольку его стандартный ввод подключен к каналу, а не к терминалу. Вы можете сначала сохранить вывод tty в переменной, например tty=$(tty);echo ee|tee $tty|foo. - person Chris; 05.02.2019
comment
@Chris Вы наблюдали такое поведение? Это было бы неожиданно. Команды раскрываются, когда оболочка анализирует всю строку до выполнения конвейера, а не позже. - person jlliagre; 05.02.2019
comment
@jlliagre Да, я наблюдал это на Centos 7, а также на Cygwin. Команды в подстановке команд наследуют стандартный ввод от родителя: например, в echo 'ls'|$(cat), cat потребляет стандартный ввод, $(cat) расширяется до ls, а конечный результат этой команды эквивалентен ls. - person Chris; 05.02.2019
comment
@Chris О, я должен был проверить. Вы абсолютно правы. Ответ исправлен. - person jlliagre; 05.02.2019
comment
Я теряю цвет, когда делаю echo 123 | grep 3 | tee /dev/tty по сравнению с echo 123 | grep 3. Как я могу получить тот же эффект, но с цветом? - person vstepaniuk; 06.10.2019

Еще одна вещь, которую стоит попробовать:

echo 'ee' | tee >(foo)

>(foo) - это подстановка процесса.

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

echo ee | tee >(wc | grep 1)
#              ^^^^^^^^^^^^^^ => child process

За исключением того, что любые объявления / изменения переменных в дочернем процессе не отражаются в родительском процессе, очень мало проблем, связанных с выполнением команд в дочернем процессе.

person bmk    schedule 15.04.2011
comment
что, если я хочу передать вывод foo по конвейеру на другой бар? - person Jack Tang; 10.10.2014
comment
@JackTang - Я думаю, что дальнейшая обработка вывода foo должна быть частью подстановки процесса. Вот пример: echo 'ee' | tee file.txt >(wc -c | tr -d ' ') - person Nick Chammas; 16.10.2014
comment
Это было решение для меня во FreeBSD (без / dev / tty) - person Paul Bissex; 25.01.2016
comment
@Nick Chammas, Чтобы поддерживать нормальный конвейер, вы можете поменять местами выходы tee: echo 'ee' | tee >(cat) | foo | bar. - person Vaelus; 31.10.2017
comment
@Vaelus Для меня foo видит в 2 раза больше ee, и на терминале ничего не печатается. Попробуйте echo 'ee' | tee >(cat) | grep . vs. echo 'ee' | tee >(cat) | grep x. - person Marki555; 21.08.2020
comment
@ Marki555, я не могу воспроизвести ваше поведение, но, возможно, вам нужно использовать tee ›(cat -) вместо того, чтобы сказать cat читать из stdin. - person Vaelus; 21.08.2020
comment
Это напечатает приглашение еще раз между выводами, эффективно добавляя второй вывод к одному из приглашений вместо печати с начала строки терминала. - person Nakilon; 29.05.2021

Пытаться:

$ echo 'ee' | tee /dev/stderr | foo

Если, конечно, можно использовать stderr.

person Jan    schedule 15.04.2011

Доступ к «/ dev / stdout» запрещен в некоторых системах, но доступ к пользовательскому терминалу предоставляется «/ dev / tty». Используя "wc" вместо "foo", приведенные выше примеры работают нормально (в Linux, OSX и т. Д.) Как:

% echo 'Hi' | tee /dev/tty | wc Hi 1 1 3

Чтобы добавить счетчик в конец списка совпадающих файлов, я использую что-то вроде:
% ls [A-J]* | tee /dev/tty | wc -l

Чтобы не запоминать все это, я определяю псевдонимы:
% alias t tee /dev/tty
% alias wcl wc -l

так что я могу просто сказать:
% ls [A-J]* | t | wcl


ПОДСКАЗКА: Для более молодых людей, которые могут хихикать при произношении "titty", я могу добавить, что "tty" когда-то было обычным сокращением для терминала "телетайп", который использовал рулон желтой бумаги и имел круглую ключи, которые часто застревают.

person user51527    schedule 02.04.2015

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

tty

затем вы можете передать вывод на этот терминал и передать другую копию через свою программу foo:

echo ee | tee /dev/pty/2 | foo
person Michael Martinez    schedule 02.08.2013
comment
oneliner: t = $ (tty) echo ee | тройник $ t | foo | бар - person Jack Tang; 10.10.2014
comment
@JackTang Это действительно лучше, но t бесполезно. Вы можете использовать echo ee | tee $(tty) | foo, но у него все еще есть бесполезная команда (tty), учитывая тот факт, что /dev/tty просто работает. - person jlliagre; 25.10.2014