Linux 将stdout传递给同一个命令两次

Linux 将stdout传递给同一个命令两次,linux,bash,Linux,Bash,您好,我对如何将stdout两次传递给同一个命令感兴趣 例如,如果我运行以下命令: seq 5 >a tac a >b paste a b 然后我得到: 1 5 2 4 3 3 4 2 5 1 以下内容也提供了相同的结果: paste <(seq 5) <(seq 5 |tac) 或 我希望某种类型的文件描述符操作或进一步的进程替换魔术会起作用,但我很难做到这一点。除非使用tee等工具,否则无法复制单个流。

您好,我对如何将stdout两次传递给同一个命令感兴趣

例如,如果我运行以下命令:

seq 5 >a
tac a >b
paste a b
然后我得到:

1       5
2       4
3       3
4       2
5       1
以下内容也提供了相同的结果:

paste <(seq 5) <(seq 5 |tac)


我希望某种类型的文件描述符操作或进一步的进程替换魔术会起作用,但我很难做到这一点。

除非使用
tee
等工具,否则无法复制单个流。一种常见的安排是使用临时文件

#!/bin/bash
t=$(mktemp -t pastepaste.XXXXXXXXXX) || exit
trap 'rm -f "$t"' ERR EXIT
tee "$t" |
paste - <(tac "$t")
#/bin/bash
t=$(mktemp-t pastepaste.xxxxxxxxx)| |退出
陷阱“rm-f”$t”错误退出
t恤“$t”|

粘贴-您可以执行以下操作:

rootdir=$(mktemp -d)  # Strictly speaking not needed, but we create us a tempdir
mkfifo "$rootdir/pipe"  # create a named pipe
seq 5 | tee "$rootdir/pipe" | paste - <(tac "$rootdir/pipe")
# We could now tee (split) output into that pipe
rm -Rf "$rootdir"  # cleanup
创建临时文件并打开fd 3进行读/写。一旦有了文件描述符,我们就不再需要文件系统中该文件的名称

seq 5 | tee /proc/self/fd/3 | paste - <(tac </proc/self/fd/3)

seq 5 | tee/proc/self/fd/3 | paste-您面临的问题是管道中的每个元素都在一个单独的子shell中执行,因此这些元素新重定向的fd不会反映在父shell中,而父shell正在执行所有I/O协调

其他一些大师可能会想出一个神奇的重定向咒语来在父级解决这个问题,但为了清楚起见,我建议使用命名管道(也称为FIFO)。因为它们存在于shell环境之外,所以它们对所有管道元素始终可见

更重要的是,通过正确的命名,“连接管道”成为一个相对没有bug的过程,尤其是当管道“网络”变得更加复杂时。没有关于哪个FD携带哪个输出的猜测游戏

对于您的示例,这可以无缝地工作:

#!/bin/bash
# Make a temp dir...
tmpd=$(mktemp -d)
# ...and clean it up automatically
trap 'rm -fr $tmpd' EXIT

# Create the FIFO...
mkfifo $tmpd/tac.fifo
# ...and PROFIT!
seq 5 | tee >(tac >$tmpd/tac.fifo) | paste - $tmpd/tac.fifo
进一步阅读:

    • 一个简单、对称的示例是使用两个命名管道

       trap 'rm p1 p2' ERR EXIT
       mkfifo p1 p2
      
      然后您可以让
      tac
      tee
      的输出过滤到
      p2

       seq 5 | tee p1 <(tac > p2) > /dev/null &
       paste p1 p2
      

      如果没有
      trap
      ,在第一个场景中出现错误或中断时,您将留下临时文件。@tripleee不,在第二个示例中不会,除非shell在
      mktemp
      rm
      之间退出。我滥用了这样一个事实,即
      取消链接
      只会删除引用,但只要fd对其打开,文件就会保持原样。这可能发生在
      mktemp
      trap
      之间,因此不需要设置它。在第一个场景中,正如我所说,如果脚本被中断,
      rm-Rf
      将不会发生。在实践中,创建目录和设置陷阱之间的竞争条件通常会被轻率地忽略,尽管我想你也可以用另一种方式来做。在第二种情况下,正如我所说,这不值得担心。所以我们是一致的。老实说,我更喜欢悬空的文件描述符而不是陷阱,它看起来有点整洁。这些都不是真正的脚本,只是交互式shell上的示例,因此关注点(尽管受到重视,但并非完全错误)就更不相关了。
      seq 5 | tee /proc/self/fd/3 | paste - <(tac </proc/self/fd/3)
      
      #!/bin/bash
      # Make a temp dir...
      tmpd=$(mktemp -d)
      # ...and clean it up automatically
      trap 'rm -fr $tmpd' EXIT
      
      # Create the FIFO...
      mkfifo $tmpd/tac.fifo
      # ...and PROFIT!
      seq 5 | tee >(tac >$tmpd/tac.fifo) | paste - $tmpd/tac.fifo
      
       trap 'rm p1 p2' ERR EXIT
       mkfifo p1 p2
      
       seq 5 | tee p1 <(tac > p2) > /dev/null &
       paste p1 p2
      
      seq 5 | tee p1 p2 > /dev/null
      paste p1 <(tac p2)