具有流程替代的输出订单


11

这是我通常在文件上运行grepwc无需扫描两次的工作

<file.txt  tee >(grep LITERAL) >(wc -l) >/dev/null

但是,这产生了

EXEC LITERAL
32

有时和

32
EXEC LITERAL

在其他时间。(第一个实例的输出grepwc于,第二个实例的反之亦然。)

另一方面,带有重定向和文件描述符

{ { <file.txt tee /dev/fd/3 | grep LITERAL >&4; } 3>&1 | wc -l ;} 4>&1 

我总是似乎得到

EXEC LITERAL
32

我更喜欢输出顺序是可预测的,但是第二种方法可以保证吗?

Answers:


4

同时

<file.txt  tee >(grep LITERAL) >(wc -l) >/dev/null

和:

{ { <file.txt tee /dev/fd/3 | grep LITERAL >&4; } 3>&1 | wc -l ;} 4>&1

所有的teegrep并且wc是同时启动。那么重要的是最后会发生什么。

wc仅当在标准输入上看到文件结尾时才打印结果。在第一种情况下,这是tee退出的时间,因为这时teefdwc正在读取的管道的另一端将其关闭(由进程替换开始)。无法保证grep届时将读取其所有输入,更不用说写入其输出了(假设管道可以容纳大量数据,并且wc可能比更快grep

在第二种情况下,wc当正在读取的管道的所有编写器都已关闭管道末端时,将看到文件结尾。在那种情况下,有几位作家。tee(通过其fd在/dev/fd/3fd 3 上打开并通过其fd 3 打开),并且其3 grepfd向管道开放wc(尽管它没有使用它,更不用说写了)。内部{可能会导致额外的subshel​​l进程,该进程还将fd打开3并等待teegrep

这意味着wc仅在grep退出后才写入其行号。

如果您编写了正确的方法,那就是关闭不需要打开的fds:

{ { <file.txt tee /dev/fd/3 4>&- | 
   grep LITERAL >&4 3>&- 4>&-; } 3>&1 | wc -l 4>&-;} 4>&1

这样一来,在优化子外壳程序的外壳程序中就无法保证顺序。但是,我所知道的唯一外壳是ksh93ksh93对管道使用套接字对,因此/dev/fd/3至少在Linux上无法使用。

要查看正在运行的进程,可以替换grepps

$ { { <file.txt tee /dev/fd/3 4>&- | ps -H >&4 3>&- 4>&-; } 3>&1 | wc -l 4>&-;} 4>&1
  PID TTY          TIME CMD
 8727 pts/5    00:00:00 bash
 8815 pts/5    00:00:00   bash
 8817 pts/5    00:00:00     tee
 8818 pts/5    00:00:00     ps
 8816 pts/5    00:00:00   wc

使用bash,您可以看到额外的shell进程,还可以看到它在fd 3上打开了管道,其中包括:

$ (p=$BASHPID; { { <file.txt tee /dev/fd/3 4>&- | lsof -ag "$p" -d3 >&4 3>&- 4>&-; } 3>&1 | wc -l 4>&-;} 4>&1)
COMMAND  PID PGID     USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
bash    9843 9842 chazelas    3w  FIFO    0,8      0t0 153304 pipe
tee     9845 9842 chazelas    3w  FIFO    0,8      0t0 153304 pipe
lsof    9846 9842 chazelas    3r   DIR    0,3        0      1 /proc

谢谢。在您的“正确示例”中,grep LITERAL >&4 3>&- 4>&-fd 4似乎既被使用又被关闭?
iruvar

@ 1_CR,之后>&4,对于短1>&4grep的的fd 1和4点到同一资源(shell的初始标准输出)。grep不需要将其fd 4开放给任何东西。它不会用它做任何事情,所以我们与关闭4>&-
斯特凡Chazelas

最后一个命令行是神秘的魔术。

-1

要获得可预测的订单,请使用

(<file.txt  tee >(grep LITERAL) >(wc -l) >/dev/null)|sort

也许我还不够清楚。我的意思是命令输出的顺序是可预测的(例如,从grep输出到从wc输出之前)。我不需要对合并的输出进行排序
iruvar

刚刚发现gnu.org/software/bash/manual/bashref.html#Command-Grouping,它告诉我使用{}运算符可确保(在这种情况下)您首先要做<file.txt tee / dev / fd / 3 | grep文学>&4; 完成此操作后,您致电wc,以便回答您的​​原始问题,是的,根据我的理解,这是可以保证的
Thorsten Staerk

1
@ThorstenStaerk您可以将找到的额外信息添加到答案中吗?
terdon

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.