“ tee”的目的是什么?


90

tee我见过的所有用法都是这样的:

 do_something | tee -a logfile

要么:

do_something_else | tee logfile

tee为那些不知道您可以使用Shell管道重定向进行相同操作的人发明的吗?如:

do_something >> logfile

要么:

do_something_else > logfile

几乎相同,敲击键盘所需的时间更少。我看不到哪些隐藏功能tee


62
手册页的第一行“ ...并写入标准输出和文件”怎么没有回答?答案很有趣,但是从广义上讲管道是如何有用的只是加强了这个Q看起来太宽泛,也许应该被封闭了。
Xen2050

3
@ Xen2050答案太宽泛不能怪问题。这个问题非常具体,当前的最高评分答案也是如此
乔恩·本特利

1
@JonBentley,这个问题听起来不像是“一个具体问题,具有足够的细节来确定适当的答案”(如关闭对话框中所示)。听起来确实像是这样:“如果您的问题可以被整本书回答,或者有许多有效答案(但无法确定哪个是正确的),那么对于我们的格式来说可能太宽泛了。” (来源:帮助中心
Xen2050 '18年

4
@ Xen2050我们在读同样的问题吗?对我来说似乎很具体-三通和管道有什么区别?使用两个句子已充分回答了该问题。远非一本书。一些答案选择切线,这一事实与问题的范围无关。
乔恩·本特利

@JonBentley:我们在读同样的问题吗?R Moog之类的问题意味着一个相当明确的问题— I / O重定向tee I / O重定向之间有什么区别  它说“ shell 管道重定向,如>>>” 这一事实并不是对其有利的观点,并且是关闭尚不清楚的理由。但是它实际上提出了多个问题:“的目的是tee什么?”,“是tee为不知道您可以使用Shell管道重定向实现相同目的的人发明的?”和“我看不到哪些隐藏功能tee?”。这些问题中至少有两个过于笼统。
G-Man

Answers:


242

您看不到的是do_something | tee -a logfile将输出放入stdout logfile 放入stdout,而do_something >> logfile将其放入日志文件。

的目的tee是产生一个输入,多个输出的场景-就像在“ T”形交叉中一样。

编辑

关于如何tee启用更加隐蔽的使用的观点已有评论sudo。这不是重点:catdd或者buffer,如果不需要多个输出,或者更好地为这种可能性提供更好的性能。使用tee它所设计,而不是什么“也可以做”


37
多个输出是关键。tee甚至可以接受多个参数并一次写入多个文件。
卡米尔Maciorowski

20
我将其称为三通管件,而不是交叉点(例如在十字路口?)。东西以一种方式进入,并且以两种方式流出。
user20574'9

7
我将如何cat直接使用而不是tee例如eg echo /var/work/core.%p | sudo tee /proc/sys/kernel/core_patternecho /var/work/core.%p | sudo cat > /proc/sys/kernel/core_pattern不起作用,因为重定向是由非sudo shell处理的。至于ddecho /var/work/core.%p | sudo dd of=/proc/sys/kernel/core_pattern工作,但dd往往是能够特别是在做很大的破坏,一个过于强大的工具sudo。至于buffer,它没有默认安装在我要处理的任何基于RedHat或Ubuntu的发行版中(或MacOS)...
Digital Trauma

3
@EugenRieck我确实了解了in:out是主要功能之间的1:n关系。但是,在这种情况下,内置函数cat/bin/cat对我都不起作用。不管cat来自何处- >仍将由顶级(非sudo)shell处理。在这种情况下,teeover 的优点cat是它允许将输出文件作为命令行参数(而不是重定向)进行传递。 dd当然是一个可行的选择,尽管我仍然tee对此表示赞同
Digital Trauma

3
@EugenRieck什么壳具有cattee作为内建?哪些版本sudo可以运行shell内置程序?
wjandrea

118

Tee 不是没有用的

也许您知道吗?如果没有,请继续阅读!或者,如果您知道它是如何工作的,但是不确定为什么它存在,请跳到最后,看看它如何与Unix哲学相适应。

什么目的tee

最简单的方法是,将标准输入上的数据写入标准输出和一个(或多个)文件。它已被比作管道三通,将一个输入分成两个输出(和两个方向)。

例子

让我们举第一个例子:

do_something | tee -a logfile

这将获取输出do_something并将其附加到日志文件,同时还将其显示给用户。实际上,Wikipedia页面上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"

此示例显示tee用于绕过sudo命令中的固有限制。sudo无法将标准输出传递到文件。通过将其标准输出流转储到中/dev/null,我们还抑制了控制台中的镜像输出。通过将用户的公共密钥安装到服务器的密钥授权列表中,上述命令使当前用户可以通过ssh通过根访问服务器。

或者,也许您想采用一个命令的输出,将其写在某个地方,然后将其用作另一命令的输入?

您也可以使用tee命令将命令的输出存储到文件中,并将相同的输出重定向为另一个命令的输入。

以下命令将备份crontab条目,并将crontab条目作为输入传递给sed命令,该命令将执行替换操作。替换后,它将作为新的cron作业添加。

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

(记入Tee命令用法示例

Tee 使用Unix原理:

编写可以做一件事并且做得很好的程序。编写程序以协同工作。编写程序来处理文本流,因为这是一个通用接口。

Unix哲学基础知识

tee 适合所有这些:

  • 它做一件事:创建输入的额外副本
  • 它可以与其他程序一起使用,因为胶水(或者,如果愿意,可以使用“ T”形管道)可以使其他程序如上例所示一起工作
  • 它通过处理标准输入上给出的文本流来实现

3
@Joe:sudo tee -a可能是一个更近的创新(我第一次看到它在Ubuntu指南/维基尤其是在设置的东西/proc/sys,因为在切换到Ubuntu的是,当我切换到一个sudo基于系统(Ubuntu是如何默认配置),而不是使用su与根密码)。我认为是tee过时的sudo,所以这不是存在的理由tee。您不需要这样做tee,交互式键入要比短sudo sh -c 'cat > output'
彼得·科德斯

1
使用bash这样的现代shell,您可以tee提供两条管道,例如foo | tee >(pipe2) | pipe1。另一个有趣的是ffmpeg ... |& tee /dev/tty | sed 's/.*\r// > encode.log,可以在tty上以交互方式查看状态行,同时删除以回车而不是换行符结尾的“行”,以进行实际的日志记录。(即过滤掉状态行更新)。通常,您可以tee /dev/tty将管道中的任何位置粘贴为调试打印。
彼得·科德斯

2
它不是您正在使用的sudo的限制,而是外壳程序对>的解释的限制。当您使用sudo运行命令时,其stdout将发送回您的Shell程序,并使用Shell的权限运行带有>的进一步重定向。如果要使用提升的权限进行编写,则需要使管道的提升部分成为编写内容。有多种方法可以做到这一点,具体取决于要达到的效果。如果您真的想使用>诸如'sudo bash -c“ command> outfile”“之类的东西,就可以完成工作。
珀金斯

确实是@Perkins。shell >在sudo甚至获取exec'd 之前解析了并设置了重定向,因此它不处理从未见过的事情绝对不是sudo的限制。:)我在解释时通常会尝试将其称为“ sudo工作流​​程”或类似术语,而不是描述sudo本身。
dannysauer

sudo tee -a恕我直言,滥用三通。如果不需要多个输出sudo cat,请使用sudo dd或(在许多情况下,其性能最好)sudo buffer
Eugen Rieck

70

几乎相同,敲击键盘所需的时间更少。

根本不一样...

以下内容似乎是等效的,但并非相同:

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

关键的区别在于,前者仅将数据写入命名文件,而后者仅将数据写入hi终端(stdout命名文件,如下所示:

重定向与tee


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

也可以使用execwith tee将脚本的所有输出记录到文件中,同时仍然允许观察者(stdout)查看数据:

exec > >( tee output.log )

2
不要忘记exec > >(tee "$LOGFILE") 2>&1在bash脚本中,该脚本允许脚本将stdout和stderr输出到stdout和指向的文件$LOGFILE
rexkogitans

@rexkogitans 2>&1这不是cmd批处理语法吗?
dmb

@dmb:这是“将stderr(= 2)发送到与stdout(= 1)相同的位置”的shell语法
psmears

@rexkogitans确实,这是一个公平的问题,我真的不知道您已经十年没有使用“ Windoze”了。我2>&1过去常常在Windows中删除输出并改写为txt文件。
dmb

1
@dmb对不起,我很抱歉。都是关于psmears的评论。显然,Windows在这里采用了Unix风格。
rexkogitans

27

这是一个三通:
在此处输入图片说明

T形管件。它具有一个入口和两个独立的出口。
换句话说,它将一个管道分成两部分;就像叉子在路上。

同样,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

4
+1图片据我们所知值得一千个单词
Sergiy Kolodyazhnyy 18/09/14

如果您选择了花园水管T恤,那么您将与道格·麦克罗伊(Doug McIlroy)的原始比喻保持一致。
JdeBP

@JdeBP对不起,我不知道那是谁。他是该实用程序的原始作者吗?通常将数据流和物理电流与液压系统进行比较,但是您可能知道这一点。无论如何,我只是选择了这种样式以使其保持超级简单。我实际上是要这样做,以使其熟悉,但是花园品种倾向于具有更多的Y形和/或视觉上复杂的附件,用于附加配件等。但是基本上是相同的。
tjt263 '18


18

不。您碰巧提到了几个示例,您实际上可以使用>>>运算符将其重定向到文件。

但是Tee可以做的更多。因为您通过管道传输到管道,所以可以管道传输到其他管道。

维基百科页面上列出了一个很好的例子:

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

基本上,您可以通过管道传输到Tee,因此可以从Tee管道传输到其他对象。如果您只想写一个日志文件,是的,那么您实际上并不需要Tee。


17

tee绝不是没有用的。我一直在使用它,并且很高兴它的存在。如果您有要拆分的管道,这是一个非常有用的工具。一个非常简单的示例是,您有一些$d要压缩的目录,并且还希望对其进行哈希处理,因为您很疑惑(就像我一样),并且不信任存储介质来可靠地保存数据。您可以先将其写入磁盘,然后再对其进行哈希处理,但是如果存档在哈希处理之前被破坏,则该操作将失败。此外,您必须阅读它,并且如果要处理大量数百GB的文件,您将知道,如果不是必须的话,您真的不想再次阅读它们。

所以我要做的就是这样:

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

它创建了tar球并将其输送到T形管,然后将其输送到两个子壳,其中一个被散列,另一个被写入磁盘。

如果要对一个大文件执行几个操作,那也很好:

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

读取一次文件,对其进行哈希处理(以便您可以检查它是否仍应保持原状),提取文件,然后将其复制到其他位置。无需为此阅读三遍。


3
Nitpick:tee不创建子壳;调用shell运行sha5sumcat并连接它们的输出到文件,该文件被传递给描述符tee。还有,对cat; 的无用使用;您可以使用输入重定向tee直接从中读取file.tar.gz
chepner

@chepner您对第一个感叹词是正确的,但是对于第二个感叹词则完全错误。我喜欢按顺序编写管道,因此,在右侧表示输入对可读性很糟糕,这样做显然在客观上逊于我的方法,完全不是我的主观偏爱。cat是爱。cat是生命。
UTF-8

6
< file.tar.gz tee >(sha256sum) ...如果您担心重定向的词法顺序,也可以编写。但这并没有改变这样一个事实,即不需要将文件完全馈入到一个完全独立的过程中tee
chepner

1
@chepner酷,谢谢!今天学到一些东西。:)
UTF-8

1
启动 成本cat相对较低。对于建议的大型文件示例,额外的100 GiB读写+系统调用成本无疑浪费了额外的CPU时间和内存带宽。请记住,内存带宽是所有内核之间的共享资源,更不用说复制会给L3缓存带来额外的污染。在启用了Spectre + Meltdown缓解的x86上,系统调用比以前昂贵。在该复制过程中,您正在消耗大量的额外CPU时间。也>(cat > foo)没有比接受教育更明白foo,IMO。
彼得·科德斯

12

Nitpick在@bertieb的回答中说,此示例显示tee被用来绕过sudo命令中的固有限制。sudo无法将标准输出传递到文件。

没有固有的限制,只是对命令的处理方式有误解。

例:

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

当前外壳解析命令行。它找到输出重定向并执行该操作。然后,它执行命令,sudo并提供其余命令行作为已执行命令的参数。如果当前shell没有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权限。


2
另外,您可能需要sudo该命令,而不需要输出文件,并且重定向也可以正常工作:sudo foo-needs-privilege > /tmp/this-output-file-doesnt
Dennis Williamson

10

正如其他人所提到的那样,tee将输出管道传递给命令会将其输出到文件和stdout中。

tee当我想从需要花费很长时间才能运行的命令中捕获输出时,也想在命令使输出可用时以视觉方式对其进行检查时,我经常使用。这样,在检查输出之前,不必等待命令完成运行。

似乎还没有提到(除非我错过了),该tee命令还可以一次写入多个文件。例如:

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

将同时将*.png当前目录中的所有文件写到两个不同的文件(a.txtb.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”语句

tee也是Unix中制作多个相同文件的最佳方法。我偶尔用它来制作多个空文件,像这样...

:|tee file01 file02 file03

5
为什么不touch呢?(更明显的是发生了什么)
Attie

@Attie touch将不会截断文件(如果它们已经存在),而只会更新其时间戳并保留其内容;但tee会截断它们。此外,执行rm+ touch不同于tee(考虑硬链接和符号链接)
Matija Nalis

那为什么不truncate -s 0呢?:-)
Attie

1

想象一下,您想将命令的输出写入日志文件打印到stdout。当您需要同时执行此操作时,则需要tee

用例是具有将整个构建都写到stdout的构建脚本(例如,对于Jenkins),但同时将重要内容写入单独的日志文件(用于摘要电子邮件)。

tee当您必须在Windows中编写脚本时,您将真正开始失踪。没有tee,那真的很烦。


创建起来很简单吗?
Lightness Races in Orbit

对于batch / cmd,这是不可能的,因为您不能轻易地拆分命令的输出流。
domih

没错,但就像三行C ++程序...
Lightness Races in Orbit

1
Windows unxutils发行版具有许多Unix命令行工具,与某些发行版不同,它们不会污染Windows执行环境。最大的限制是“ glob” bing,它在Unix / Linux和Windows上的工作方式不同。“ tee”是可用的工具之一。
cmm

2
别傻了,这是2018年。使用Powershell,它有tee。Cmd从未打算用于认真的脚本编写-这就是VBS的目的。Powershell是新的入门脚本工具。当然,Cmd仍然很强大,但是命令行工具却很少。
六安'18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.