ダッシュ:STDINを複数のコマンドにパイプし、その出力を定義された順序でSTDOUTにパイプします。

ダッシュ:STDINを複数のコマンドにパイプし、その出力を定義された順序でSTDOUTにパイプします。

最初に私は思ったこの回答解決策がありますが、今はバッファとして使用する一時ファイルが必要なようです。

これは信頼できないように動作します。

#!/bin/sh
echo 'OK' |
{
    {
        tee /dev/fd/3 | head --bytes=1 >&4
    } 3>&1 | tail --bytes=+2 >&4
} 4>&1

端末でこれを実行すると、次のような結果が表示されます。

いいね

時々私は次を得ます:


カリウム

完全にランダムに見えます。そのため、回避策として出力をファイルに書き込み、パイプラインが完了したらもう一度tail読み込みます。stdout

#!/bin/sh
echo 'OK' |
{
    {
        tee /dev/fd/3 | head --bytes=1 >&4
    } 3>&1 | tail --bytes=+2 >file
} 4>&1
cat file

dash一時ファイルなしでこれを実行できますか?出力にNULバイトを含めることができるため、バッファとしてのシェル変数もオプションではありません。

ベストアンサー1

消費者と生産者を並列に実行しても消費者の出力をシリアル化する場合は、2番目の消費者の出力を遅らせる必要があります。これを行うには、出力を何とか保存する必要があります。最良の方法は一時ファイルを使用することです。

そしてzsh

{cat =(producer > >(consumer1 >&3) | consumer2)} 3>&1

bashプロセス交換コマンドを待たないため、問題があるため、そこに不快な回避策を使用する必要があります。

ここでは、=(...)プロセス置換形式を使用して出力を保存する前にcomsumer2一時ファイルに保存しますcat。 2人以上の消費者に対してこれを行うことはできません。これを行うには、一時ファイルを手動で作成する必要があります。

使用しない場合は、一時=(...)ファイルを手動でクリーンアップする必要があります。これを事前に作成して削除して処理できるため、スクリプトが終了することを心配する必要はありません。まだありますzsh

tmp1=$(mktemp) && tmp2=$(mktemp) || exit
{
  rm -f -- $tmp1 $tmp2
  producer > >(consumer1) > >(consumer2 >&3) > >(consumer3 >&5)
  cat <&4 <&6
} 3> $tmp1 4< $tmp1 5> $tmp2 6< $tmp2

dash編集(最初は解決策が必要だという事実を見逃しました)

dash(または2つ以上のfdsにclose-on-execフラグを設定せずにソケットペアの代わりにパイプを使用するPOSIXシェル|)とサポートされているシステムの場合/dev/fd/x

tmp1=$(mktemp) && tmp2=$(mktemp) || exit
{
  rm -f -- "$tmp1" "$tmp2"
  {
    {
      {
        producer | tee /dev/fd/4 /dev/fd/6 | consumer1 >&7
      } 4>&1 | consumer2 >&3
    } 6>&1 | consumer3 >&5
  } 7>&1
  cat - /dev/fd/6 <&4
} 3> "$tmp1" 4< "$tmp1" 5> "$tmp2" 6< "$tmp2"

Linuxではdash、、、、、、では動作しますが、bashでは動作しません。このアプローチはfds 0〜9に制限されているため、4人以上の消費者では機能できません。zshmkshbusybox shposhksh93

おすすめ記事