Какова цель «тройник»?

90

Все случаи, которые teeя когда-либо видел, были такими:

 do_something | tee -a logfile

Или же:

do_something_else | tee logfile

Является ли teeпридумано для тех, кто не знает , вы можете сделать то же самое с оболочкой трубой перенаправлениями? Такие как:

do_something >> logfile

Или же:

do_something_else > logfile

Это практически то же самое, и для набора текста требуется меньше нажатий клавиш. В каких скрытых функциях я не вижу tee?

R Moog
источник
62
Как на это не ответила самая первая строка справочной страницы "... и записать в стандартный вывод и файлы" ? Ответы интересны, но общий разговор о том, насколько полезны каналы, только подтверждает, что этот Q кажется слишком широким и, возможно, должен был быть закрыт.
Xen2050
3
@ Xen2050 Вопрос не может быть обвинен в слишком широком ответе. Вопрос очень специфический, так же как и текущий самый высокий рейтинг ответов .
Джон Бентли
1
@JonBentley вопрос не звучит как «конкретная проблема с достаточным количеством деталей, чтобы найти адекватный ответ» (как гласит диалог закрытия). Это звучит так: «если на ваш вопрос можно ответить целой книгой или у него много действительных ответов (но нет способа определить, какие из них - если они есть - правильные), то, вероятно, он слишком широк для нашего формата». (Источник: Справочный центр )
Xen2050
4
@ Xen2050 Мы читаем один и тот же вопрос? Это кажется мне очень специфичным - в чем разница между тройником и трубкой? Ответ был адекватным, используя два предложения. Далеко не вся книга. Тот факт, что некоторые ответы выбирают касательную, не имеет никакого отношения к объему вопроса.
Джон Бентли
@JonBentley: мы читаем один и тот же вопрос? R Moog добрейшей из рода- предполагает достаточно хорошо сфокусированный вопрос - какова разница между tee и I / O перенаправлением ?   Дело в том , что он говорит , «оболочка трубы переназначения , такие как >и >>» не является точкой в его пользу, и является аргументом в пользу закрытия неясной. Но на самом деле он задает несколько вопросов: «Какова цель tee?», « teeПридумано для тех, кто не знает, что вы можете сделать то же самое с перенаправлениями оболочки?» И «В каких скрытых функциях я не вижу tee?». По крайней мере, два из этих вопросов слишком широки.
G-Man

Ответы:

242

То , что вы не видите, что do_something | tee -a logfileставит вывод в logfile и на стандартный вывод, а do_something >> logfileставит его только в лог - файл.

Цель teeсостоит в том, чтобы создать сценарий с одним входом и несколькими выходами, как в пересечении «Т».

РЕДАКТИРОВАТЬ

Там были комментарии о том, как teeпозволяет более простое использование sudo. Это рядом с точкой: cat, ddили , может быть , лучше bufferпредоставить эту возможность с более высокой производительностью, если вы не нужны несколько выходов. Используйте teeдля того, для чего он предназначен, а не для того, что он «может сделать»

Евгений Рик
источник
37
Многократный вывод является ключом. teeможет даже принимать несколько аргументов и записывать сразу в несколько файлов.
Камиль Мачоровский
20
Я бы назвал это фитингом тройника , а не перекрестком (как на пересечении дорог?). Материал приходит одним способом и выходит в обоих направлениях.
user253751
7
Как бы я использовал catпрямой способ вместо, teeнапример, в echo /var/work/core.%p | sudo tee /proc/sys/kernel/core_pattern? echo /var/work/core.%p | sudo cat > /proc/sys/kernel/core_patternне работает, потому что перенаправление обрабатывается не-sudo оболочкой. Что касается dd, echo /var/work/core.%p | sudo dd of=/proc/sys/kernel/core_patternработает, но ddчасто это мощный инструмент, способный нанести большой урон, особенно под sudo. Что касается buffer, он не установлен по умолчанию ни в одном из дистрибутивов на основе RedHat или Ubuntu, которые я должен передать (или MacOS) ...
Digital Trauma
3
@EugenRieck Я понимаю, что отношение 1: n между in: out является основной функцией. Тем не менее, ни встроенный, catни /bin/catработа для меня в этой ситуации. Неважно, откуда он catберется - он >будет по-прежнему обрабатываться оболочкой верхнего уровня (не sudo). Преимущество teeover catв этой ситуации заключается в том, что он позволяет передавать выходной файл в качестве параметра командной строки (а не перенаправления). ddэто, безусловно, жизнеспособный вариант, хотя я бы все же поддержал teeэто
Digital Trauma
3
@EugenRieck Какая оболочка имеет catи teeкак встроена? А какая версия sudoможет запускать встроенные оболочки?
wjandrea
118

Tee не бесполезен

Может быть, вы знали это в любом случае? Если нет, то читайте дальше! Или, если вы знаете, как он работает, но не знаете, почему он существует, перейдите к концу, чтобы увидеть, как он вписывается в философию Unix.

Что это цель tee?

В простейшем случае он берет данные на стандартный ввод и записывает их в стандартный вывод и один (или более) файл. Его сравнивают с сантехническим тройником так, как он разделяет один вход на два выхода (и два направления).

Примеры

Давайте возьмем ваш первый пример:

do_something | tee -a logfile

Он принимает вывод do_somethingи добавляет его в файл журнала, а также отображает его для пользователя. На самом деле, страницаtee в Википедии содержит второй пример:

Чтобы просмотреть и добавить вывод команды из существующего файла:

  lint program.c | tee -a program.lint

Это отобразит стандартный вывод команды lint program.c на компьютере и в то же время добавит его копию в конец файла program.lint. Если файл program.lint не существует, он создается.

В следующем примере есть другое применение: повышение разрешений :

Чтобы разрешить эскалацию разрешений:

cat ~/.ssh/id_rsa.pub | ssh admin@server "sudo tee -a /root/.ssh/authorized_keys2 > /dev/null"

В этом примере показано, как тройник используется для обхода внутреннего ограничения в sudoкоманде. sudoне может передать стандартный вывод в файл. Выгружая его стандартный поток вывода /dev/null, мы также подавляем зеркальный вывод в консоли. Приведенная выше команда предоставляет текущему пользователю root доступ к серверу через ssh, установив открытый ключ пользователя в список авторизации ключей сервера.

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

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

Следующая команда создаст резервную копию записей crontab и передаст записи crontab в качестве команды ввода в sed, которая выполнит замену. После замены он будет добавлен в качестве нового задания cron.

$ crontab -l | tee crontab-backup.txt | sed 's/old/new/' | crontab –

(благодарю за примеры использования команды Tee )

Tee работает с философией Unix:

Напишите программы, которые делают одно и делают это хорошо. Напишите программы для совместной работы. Написание программ для обработки текстовых потоков, потому что это универсальный интерфейс.

(Благодарность основам философии Unix )

tee подходит всем этим:

  • это делает одну вещь: создает дополнительную копию ввода
  • он работает с другими программами, потому что это клей (или кусок сантехники 'T', если вы предпочитаете), который позволяет другим программам работать вместе, как в примерах выше
  • это делается путем манипулирования потоком текста, заданным на стандартном вводе
bertieb
источник
3
@Joe: sudo tee -aэто , вероятно, более недавнее нововведение (я впервые увидел его в руководствах Ubuntu / вики специально для установки вещи в /proc/sys, потому что переход на Ubuntu, когда я перешел на sudoсистему , основанную (как Ubuntu настроенном по умолчанию) вместо использования suс пароль root). Я думаю , что teeраньше sudo, так что это не причина для teeсуществования. Вам не нужно teeдля этого, просто печатать в интерактивном режиме, чем sudo sh -c 'cat > output'.
Питер Кордес
1
С современными оболочками типа bash можно teeпитать два конвейера, вроде бы foo | tee >(pipe2) | pipe1. Или еще один интересный способ - ffmpeg ... |& tee /dev/tty | sed 's/.*\r// > encode.logинтерактивно видеть обновления строки состояния на tty, при этом удаляя «строки», заканчивающиеся символом возврата каретки, а не символом новой строки для фактической регистрации. (т.е. отфильтровывать обновления строки состояния). В общем, вы можете прикрепить tee /dev/ttyлюбое место в конвейере как отладочную печать.
Питер Кордес
2
Это не ограничение sudo, над которым вы работаете, а ограничение оболочки>. Когда вы запускаете команду с помощью sudo, ее стандартный вывод отправляется обратно в вашу программу оболочки, а дальнейшие перенаправления с помощью> запускаются с разрешениями оболочки. Если вы хотите писать с повышенными правами доступа, вам нужно иметь повышенную часть конвейера, которая будет писать. Есть много способов сделать это в зависимости от того, какой именно эффект вы собираетесь получить. Если вы действительно хотите использовать> что-то вроде 'sudo bash -c "command> outfile"', то сделайте это.
Perkins
Точно, @Perkins. Оболочка анализирует >и устанавливает перенаправление до того, как sudo даже получит exec, поэтому определенно не является ограничением sudo, что она не обрабатывает вещи, которые никогда не видит. :) Обычно я пытаюсь обозначить это как «рабочий процесс sudo» или какой-то подобный термин, когда я объясняю это, а не описывать само sudo.
dannysauer
sudo tee -aЭто ИМХО злоупотребление тройником. Использованию sudo cat, sudo ddили (с лучшей производительностью во многих случаях) , sudo bufferесли вам не нужно несколько выходов.
Евгений Рик,
70

Это практически то же самое, и для набора текста требуется меньше нажатий клавиш.

Это совсем не то же самое ...

Следующее представляется несколько эквивалентным, но это не так:

$ echo "hi" > test.txt
$ echo "hi" | tee test.txt
hi

Критическое различие заключается в том, что первый записал данные только в именованный файл, а последний записал hiв терминал ( stdout) и названный файл, как показано ниже:

перенаправление против тройника


teeпозволяет вам записывать данные в файл и использовать их в последующем конвейере, что позволяет вам делать полезные вещи, такие как хранение данных из частично через конвейер:

grep '^look ' interesting_file.txt \
  | tee interesting_lines.txt \
  | sort

Или вы можете записать в файл с повышенными привилегиями, не предоставляя всему конвейеру повышенные привилегии (здесь echoзапускается как пользователь, а teeзаписывает в файл как root):

echo 0 \
  | sudo tee /proc/sys/net/ipv4/ip_forward

С помощью teeвы можете записать много файлов ( и stdout ):

echo "hi" \
  | tee a.txt b.txt

Также можно использовать execс, teeчтобы записать весь вывод скрипта в файл, при этом позволяя наблюдателю ( stdout) видеть данные:

exec > >( tee output.log )
Attie
источник
2
Не exec > >(tee "$LOGFILE") 2>&1стоит забывать в скрипте bash, который позволяет скрипту выводить stdout и stderr как в stdout, так и в файл, на который указывает $LOGFILE.
rexkogitans
@rexkogitans 2> & 1 разве это не командный синтаксис cmd?
августа
@dmb: это синтаксис оболочки для «отправки stderr (= 2) в то же место, что и stdout (= 1)»
psmears
@rexkogitans Это был честный вопрос на самом деле, я не могу точно знать, что вы не использовали "Windoze" в течение десятилетия. Я использую, 2>&1чтобы сбросить вывод и ошибки в текстовые файлы в Windows.
августа
1
@dmb Прошу прощения за грубость. Это все о комментарии psmears. Очевидно, что Windows приняла Unix-стиль здесь.
rexkogitans
27

Это тройник:
введите описание изображения здесь

Т-образный фитинг. Он имеет вход и два отдельных выхода.
Другими словами, он разделяет одну трубу на две; как развилка на дороге.

Аналогично, teeэто pipe ( |), который позволяет перенаправлять ваш стандартный ввод на два отдельных выхода.


Пример
Скажем, например, вы печатаете ls /.
Вы получите вывод, который выглядит примерно так:

Applications    Network     Users       bin        dev      net      private    tmp         var
Library         System      Volumes     cores      etc      home     opt        sbin        usr

Перенаправьте вывод в текстовый файл, ls / > ls.txtи вывод не отображается в оболочке, только в результирующем текстовом файле.

Хотите увидеть вывод и одновременно передать его в текстовый файл?
Добавьте teeк своей трубе ( |) то есть:ls / | tee ls.txt


Сравните два:

ls /          >          ls.txt
ls /        | tee        ls.txt
голоса
источник
4
+1 за картину, которая, как мы знаем, стоит тысячи слов
Сергей Колодяжный,
Если бы вы выбрали тройник садового шланга, вы бы согласились с оригинальной метафорой Дуга Макилроя.
JdeBP
@JdeBP Извините, я понятия не имею, кто это. Он оригинальный автор утилиты или что-то? Поток данных и физический электрический ток часто сравнивают с гидравлическими системами, но вы, вероятно, знаете это. Во всяком случае, я просто выбрал этот стиль, чтобы сделать его очень простым. На самом деле я собирался сделать это, чтобы держать его в курсе, но у садового сорта, как правило, больше Y-образных и / или визуально сложных приспособлений для крепления аксессуаров и т. Д. По сути, это то же самое.
голоса
18

Нет. Вы упомянули один из немногих примеров, где вы действительно можете перенаправить на файл с помощью операторов >and >>.

Но Ти может сделать гораздо больше. Поскольку вы направляетесь к нему по трубопроводу, вы можете затем передавать по трубопроводу что-то еще.

Хороший пример приведен на странице википедии :

find "4DOS" wikipedia.txt | tee 4DOS.txt | sort > 4DOSsorted.txt

По сути, вы можете передавать по трубопроводу к Tee, а затем по трубопроводу от Tee к чему-то еще. Если все, что вы хотите сделать, это написать файл журнала, да, тогда вам не нужен Tee.

LPChip
источник
17

teeдалеко не бесполезен. Я использую это все время и рад, что это существует. Это очень полезный инструмент, если у вас есть конвейер, который вы хотите разделить. Очень простой пример: у вас есть какой-то каталог, $dкоторый вы хотите скопировать, и вы также хотите его хэшировать, потому что вы параноик (как и я) и не доверяете носителю для надежного хранения данных. Вы можете сначала записать его на диск, а затем хэшировать, но это не получится, если архив будет поврежден до того, как будет хеширован. Кроме того, вам придется прочитать его, и если вы будете много работать с файлами размером в несколько сотен ГБ, вы поймете, что действительно не хотите читать их снова, если этого не требуется.

Так что я делаю просто так:

tar -c "$d" | tee >(sha256sum) >(cat > "$d"".tar") > /dev/null

Он создает тарный шарик и направляет его в тройник, который затем направляет его в две вложенные оболочки, в одной из которых он хэшируется, а в другой - записывается на диск.

Также замечательно, если вы хотите выполнить несколько операций с большим файлом:

< file.tar.gz tee >(sha256sum) >(tar -xz) /other/storage/location/file.tar.gz > /dev/null

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

UTF-8,
источник
3
Nitpick: teeне создает подоболочек; вызывающая оболочка запускается sha5sumи catсоединяет свои выходные данные с файловыми дескрипторами, которые передаются tee. Кроме того, бесполезное использование cat; Вы можете использовать перенаправление ввода для teeчтения непосредственно из file.tar.gz.
Чепнер
@chepner Вы правы насчет первого междометия, но совершенно не правы во втором. Мне нравится писать свои конвейеры по порядку, поэтому обозначение ввода справа ужасно для читабельности, и это явно объективно уступает моему методу и совершенно не является моим субъективным предпочтением. catэто любовь. catэто жизнь.
UTF-8
6
Вы также можете написать, < file.tar.gz tee >(sha256sum) ...если вас беспокоит лексическое упорядочение перенаправлений. Это не меняет того факта, что нет необходимости в совершенно отдельном процессе, чтобы просто передать один файл tee.
chepner
1
@chepner Круто, спасибо! Узнал что-то сегодня. :)
UTF-8
1
Стоимость запуска cat относительно низкая. Стоимость дополнительных 100 ГиБ системных вызовов write + read определенно тратит дополнительное процессорное время и пропускную способность памяти для предложенного вами примера огромного файла. Помните, что пропускная способность памяти является общим ресурсом для всех ядер, не говоря уже о дополнительном загрязнении кэша L3 в результате этого копирования. На x86 с включенным смягчением Specter + Meltdown системные вызовы обходятся дороже, чем раньше. Вы расходуете измеримое количество дополнительного процессорного времени в течение этой копии. Также >(cat > foo)не легче понять, чем foo, IMO.
Питер Кордес
12

Nitpick в ответе @ bertieb, который гласит: В этом примере показано, как тройник используется для обхода врожденного ограничения в команде sudo. sudo не может передать стандартный вывод в файл.

Не существует внутренних ограничений, только неправильное понимание того, как обрабатывается команда.

Пример:

sudo echo 0 > /proc/sys/net/ipv4/ip_forward

Текущая оболочка разбирает командную строку. Он находит перенаправление вывода и выполняет это. Затем он выполняет команду, которая является sudoи предоставляет оставшуюся командную строку в качестве аргументов для выполняемой команды. Если текущая оболочка не имеет прав доступа root, перенаправление вывода завершится ошибкой.

echo 0 | sudo tee /proc/sys/net/ipv4/ip_forward

Это работает, потому что перенаправление вывода откладывается на teeкоманду, которая на тот момент имеет права root, потому что она была выполнена с помощью sudo.

sudo bash -c "echo 0 > /proc/sys/net/ipv4/ip_forward"

Это работает, потому что у оболочки, выполняющей перенаправление, есть права root.

studog
источник
2
Кроме того, вам может понадобиться sudoкоманда, но не выходной файл, и перенаправление работает очень хорошо:sudo foo-needs-privilege > /tmp/this-output-file-doesnt
Деннис Уильямсон,
10

Как уже упоминали другие, вывод teeкоманды в команду записывает эти выходные данные как в файл, так и в стандартный вывод.

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

То, что, кажется, еще не было упомянуто (если я не пропустил это), это то, что teeкоманда также может записывать несколько файлов одновременно. Например:

ls *.png | tee a.txt b.txt

запишет все *.pngфайлы в текущем каталоге в два разных файла ( a.txtи b.txt) одновременно.

Фактически, вы можете набирать текст сразу в нескольких разных файлах teeследующим образом:

$ tee --append a.txt b.txt c.txt d.txt
These lines are appended to four different files,
and are also written to stdout.
CTRL-D
JL
источник
9

Наиболее распространенное использование tee - видеть текст на терминале одновременно с отправкой его в файл (или файлы). Формулировка вашего вопроса предполагает, что вы когда-либо пишете текст в лог-файлы. У меня есть сценарии, которые пишут списки имен файлов или каталогов для запуска файлов (для асинхронной обработки другими сценариями), и я использую tee для отправки того же контента на стандартный вывод. Весь stdout направлен на логи. Итак, у меня есть текст, где я хочу, и у меня есть запись в журнале, в которой я это сделал, все из одного утверждения 'echo'

Это также лучший метод в Unix для создания нескольких одинаковых файлов. Я иногда использую его для создания нескольких пустых файлов, как это ...

:|tee file01 file02 file03
Уил Янг
источник
5
почему нет touch? (больше сразу видно, что происходит)
Attie
@Attie touchне будет обрезать файлы, если они уже существуют, а только обновит свои временные метки и оставит их содержимое как есть; но teeобрежет их. Кроме того, выполнение rm+ touchотличается от tee(подумайте о жестких и символических
ссылках
Тогда почему нет truncate -s 0? :-)
Attie
1

Представьте, что вы хотите записать вывод команды в файл журнала и распечатать на стандартный вывод. Когда вам нужно сделать это одновременно, тогда вам нужно tee.

Вариант использования - иметь сценарии сборки, которые записывают всю сборку в стандартный вывод (например, для Jenkins), но одновременно важные вещи в отдельный файл журнала (для сводных электронных писем).

Вы действительно начнете скучать, teeкогда вам придется сценарий в Windows. Нет teeи это действительно раздражает.

domih
источник
Разве это не тривиально создавать?
Гонки
С batch / cmd это невозможно, так как вы не можете легко разделить поток вывода команды.
Домих
Правильно, но похоже на трехстрочную программу C ++ ...
Гонки на легкость на орбите
1
В дистрибутиве Windows unxutils есть много инструментов командной строки Unix, которые, в отличие от некоторых дистрибутивов, не загрязняют среду выполнения Windows. Самое большое ограничение на bing «glob», который работает в Unix / Linux иначе, чем в Windows. «тройник» является одним из доступных инструментов.
CMM
2
Не будь глупым, это 2018. Используйте Powershell, это так tee. Cmd никогда не предназначался для серьезных сценариев - для этого и был VBS. Powershell - это новый инструмент для написания скриптов. Конечно, Cmd все еще довольно мощный, но инструментов командной строки довольно мало.
Луан