Rqo*_*mey 13 grep bash pipe process-substitution tee
我没有太多使用 tee 的经验,所以我希望这不是很基本。
在查看了这个问题的一个答案后,我遇到了一个奇怪的行为tee
。
为了让我输出第一行和找到的行,我可以使用这个:
ps aux | tee >(head -n1) | grep syslog
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
syslog 806 0.0 0.0 34600 824 ? Sl Sep07 0:00 rsyslogd -c4
Run Code Online (Sandbox Code Playgroud)
然而,我第一次运行这个(在 zsh 中)结果是错误的顺序,列标题低于 grep 结果(但这并没有再次发生),所以我尝试交换命令:
ps aux | tee >(grep syslog) | head -n1
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
Run Code Online (Sandbox Code Playgroud)
只打印第一行,没有别的!我可以使用 tee 重定向到 grep,还是我以错误的方式执行此操作?
当我输入这个问题时,第二个命令实际上对我有用一次,我再次运行了五次,然后返回到一行结果。这只是我的系统吗?(我在 tmux 中运行 zsh)。
最后,为什么第一个命令没有显示“grep syslog”作为结果(只有一个结果)?
这里的控制是没有的 grep tee
ps aux | grep syslog
syslog 806 0.0 0.0 34600 824 ? Sl Sep07 0:00 rsyslogd -c4
henry 2290 0.0 0.1 95220 3092 ? Ssl Sep07 3:12 /usr/bin/pulseaudio --start --log-target=syslog
henry 15924 0.0 0.0 3128 824 pts/4 S+ 13:44 0:00 grep syslog
Run Code Online (Sandbox Code Playgroud)
更新: 似乎 head 导致整个命令截断(如下面的答案所示)下面的命令现在返回以下内容:
ps aux | tee >(grep syslog) | head -n1
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
syslog 806
Run Code Online (Sandbox Code Playgroud)
mrb*_*mrb 22
$ ps aux | tee >(head -n1) | grep syslog
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
syslog 806 0.0 0.0 34600 824 ? Sl Sep07 0:00 rsyslogd -c4
Run Code Online (Sandbox Code Playgroud)
该grep
和head
在大约同一时间开始的命令,都在自己的休闲收到相同的输入数据,但通常作为数据变为可用。有些事情可以引入翻转行的“不同步”输出;例如:
来自多路复用的数据tee
实际上先于另一个进程发送到另一个进程,这主要取决于tee
. 一个简单的tee
实现会read
输入一定量的输入,然后write
两次:一次到标准输出,一次到它的参数。这意味着这些目的地之一将首先获得数据。
但是,管道都是缓冲的。这些缓冲区很可能每个都有 1 行,但它们可能更大,这会导致其中一个接收命令grep
在另一个命令 ( head
) 收到任何数据之前看到它输出所需的所有内容(即ped 行)全部。
尽管如此,也有可能其中一个命令接收到数据但无法及时处理,然后另一个命令接收更多数据并快速处理它。
例如,即使head
和 一次grep
发送一行数据,如果head
不知道如何处理它(或被内核调度延迟),甚至可以在有机会grep
之前显示其结果head
。为了演示,尝试添加一个延迟:ps aux | tee >(sleep 1; head -n1) | grep syslog
这几乎肯定会grep
首先输出输出。
$ ps aux | tee >(grep syslog) | head -n1
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
Run Code Online (Sandbox Code Playgroud)
我相信你经常在这里只得到一行,因为head
接收第一行输入然后关闭它的标准输入并退出。当tee
看到其标准输出已关闭时,它会关闭自己的标准输入(来自 的输出ps
)并退出。这可能取决于实现。
实际上,这是唯一的数据ps
获得要发送的是第一线(当然,因为head
是控制这一点),也许有些其他行之前head
和tee
关闭他们的标准输入描述符。
第二行是否出现不一致是由时序引入的:head
关闭stdin,但ps
仍在发送数据。这两个事件没有很好地同步,因此包含的行syslog
仍然有机会使其成为tee
的参数(grep
命令)。这与上面的解释类似。
您可以通过使用在关闭标准输入/退出之前等待所有输入的命令来完全避免这个问题。例如,使用awk
代替head
,它将读取并处理其所有行(即使它们没有输出):
ps aux | tee >(grep syslog) | awk 'NR == 1'
Run Code Online (Sandbox Code Playgroud)
但请注意,这些行仍然可能出现乱序,如上所示,可以通过以下方式证明:
ps aux | tee >(grep syslog) | (sleep 1; awk 'NR == 1')
Run Code Online (Sandbox Code Playgroud)
希望这不是太多细节,但是有很多同时发生的事物相互作用。单独的进程在没有任何同步的情况下同时运行,因此它们在任何特定运行中的操作可能会有所不同;有时,深入挖掘底层流程以解释原因会有所帮助。