パイプの概念を複数の並列パイプラインに一般化するシェルはありますか? それをサポートするには OS カーネルの変更が必要ですか?

パイプの概念を複数の並列パイプラインに一般化するシェルはありますか? それをサポートするには OS カーネルの変更が必要ですか?

コマンドラインで作業しているときに、入力ストリームによって指定されたさまざまなインスタンスに対して同じ操作を指定し、それらの出力を特定の方法で再結合したいということがよくあります。

昨日の 2 つの使用例:

  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. 私たちは、ノートブック サーバーを Docker コンテナーとして分割する JupyterHub インスタンスを実行しています。タイムスタンプ付きのログを監視したいのですが、コンテナーが 1 つであれば簡単です。

     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. ツール内で任意の数の入力および出力ファイル記述子を指定して、このシェルがそれらを並列パイプラインとして扱うための固定された規則。

これはすでに実行されていますか? または、私のユースケースに適用できる同等のものはありますか?

特定のカーネル サポートなしで実現可能でしょうか? カーネルでは通常、開いているファイル記述子の最大数が固定されていることは知っていますが、実装では盲目的に一度にすべてを開こうとしないことでこれを回避できます。

それは実現可能か?GNU パラレル実現可能でしょうか?

答え1

GNU Parallel の場合:

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内容は考慮せず、パイプにはレコード区切りの範囲外を示すものはありません。

パイプのソースと宛先に特定の規則を適用することでこれを実現できますが、作成者が予期していなかったタスクの構成要素としてプログラムを組み合わせることができるというパイプの主な利点が失われます。

この特定の例では、複数のストリームを処理するように変更し、さらにこれらの複数のストリームを提供するように変更するよりも、1 つのストリームで複数の証明書を処理するように変更opensslする方がはるかに簡単です。opensslcat

関連情報