87

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

 do_something | tee -a logfile

Или же:

do_something_else | tee logfile

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

do_something >> logfile

Или же:

do_something_else > logfile

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

10 ответов10

241

То, что вы не видите, это то, что do_something | tee -a logfile помещает вывод в logfile и в stdout, тогда как do_something >> logfile помещает его только в logfile.

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

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

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

119

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', если вы предпочитаете), который позволяет другим программам работать вместе, как в примерах выше
  • это делается путем манипулирования потоком текста, заданным на стандартном вводе
69

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

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

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

$ 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 )
26

Это тройник:

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

Точно так же tee - это труба (|), которая позволяет вам перенаправить ваш стандартный ввод на два отдельных выхода.


пример
Скажем, например, вы вводите 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
18

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

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

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

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

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

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

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

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.

10

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

Я часто использую 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
9

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

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

:|tee file01 file02 file03
1

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

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

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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .