是否有 shell 将管道的概念概括为多个并行管道?支持它需要更改操作系统内核吗?

是否有 shell 将管道的概念概括为多个并行管道?支持它需要更改操作系统内核吗?

很多时候,在使用命令行时,我发现自己在某些输入流指定的一堆不同实例上指定相同的操作,然后想要以某种特定的方式重新组合它们的输出。

昨天的两个用例:

  1. 我想查看捆绑在 PEM 文件中的一堆 SSL 证书的主题。

     cat mypemfile.crt |
     (openssl x509 -noout -text | fgrep Subject:)
    

    只显示第一个。我需要拆分证书并对每个证书运行相同的命令,然后连接结果。csplit可以拆分它们,但只能拆分为文件。这就麻烦了。

    为什么我不能直接说

     cat mypemfile.crt |
     csplit-tee '/BEGIN/ .. /END/' |
     on-each ( openssl x509 -noout -text | fgrep Subject: ) |
     merge --cat
    

  2. 我们运行一个 JupyterHub 实例,将笔记本服务器拆分为 Docker 容器。我想查看他们带时间戳的日志。对于一个容器来说这很容易:

     sudo docker logs -t -f $container_id
    

    -t添加时间戳,并保持-f管道打开,就像tail -f。)

    列出所有容器的日志很容易,按时间戳排序:

     sudo docker ps | awk '{print $1}' |
     while read container_id
     do
       sudo docker logs -t $container_id
     done |
     sort
    

    或者

     sudo docker ps | awk '{print $1}' |
     xargs -n1 sudo docker logs -t |
     sort
    

    或者

     sudo docker ps | awk '{print $1}' |
     parallel sudo docker logs -t {} |
     sort
    

    但这些都不会让我使用该-f选项来观看日志。

    为什么我不能直接使用

     sudo docker ps | awk '{print $1}' |
     csplit-tee /./ |
     on-each (xargs echo | sudo docker logs -t -f) |
     merge --line-by-line --lexicographically
    

    或者

     sudo docker ps | awk '{print $1}' |
     parallel --multipipe sudo docker logs -t -f {} |
     merge --line-by-line --lexicographically
    

显然,这需要

  1. 特定的外壳支持。也许我们需要一个独特的“多管道”符号。
  2. 用于拆分和合并管道的新工具(csplit-teeon-each和)。merge
  3. 关于如何在工具内指定任意多个输入和输出文件描述符的固定约定,以便该 shell 将它们视为并行管道。

这已经做到了吗?或者我可以应用于我的用例的等效内容?

没有特定内核支持是否可行?我知道内核通常有一个固定的最大数量的打开文件描述符,但是一个实现可以通过不盲目地尝试一次打开它们来解决这个问题。

知道的话可行吗GNU并行可行吗?

答案1

使用 GNU 并行:

cat mypemfile.crt |
  parallel --pipe -N1 --recstart '-----BEGIN' 'openssl x509 -noout -text | fgrep Subject:'

未经测试:

sudo docker ps | awk '{print $1}' |
  sudo parallel -j0 --lb docker logs -t -f {}

sudo docker ps | awk '{print $1}' |
  sudo parallel -j0 --tag --lb docker logs -t -f {}

答案2

不,外壳不能做到这一点。管道只是从源到目的地的流,通常在不同的进程中。

让我们看看你的第一个例子:

cat mypemfile.crt |
(openssl x509 -noout -text | fgrep Subject:)

您希望输入文件沿着包含 BEGIN 和 END 的行进行分割,但cat不关心内容,并且管道无论如何都没有记录分隔符的越界指示。

您可以通过管道的源和目标中的特定约定来实现此目的,但这会消除管道的主要优点,即能够将程序组合为构建块,以完成其作者未预期的任务。

openssl在此特定示例中,修改以处理一个流中的多个证书比修改openssl以处理多个流并修改cat以提供这些多个流要容易得多。

相关内容