Bashスクリプトでは、ファイル名引数でプロセスstdoutを複数回開くと失敗します。

Bashスクリプトでは、ファイル名引数でプロセスstdoutを複数回開くと失敗します。

次のbashスクリプトコードを考えてみましょう。

#!/bin/bash

function bug_part() {
    cat $1 > sample.first
    cat $1 > sample.second #second time you open file $1, it contains no data
}

bug_part <(echo "TEST")
[ "$(cat sample.first)" != "$(cat sample.second)" ] && echo "THIS IS A BUG" 1>&2 && exit 1
rm sample.first sample.second

この問題がbashバグであることに同意しますか?それともLinuxのバグですか?

後ろから何が起こっているのか知っている人はいますか?

答え1

私はこれが間違いだとは思わない。次のコマンドで接続された名前付きパイプを読み書きできます。プロセスの交換一度だけ。

答え2

これはスクリプトのバグです。tee一度だけ読み取ることができるデータをコピーするには、このオプションを使用します。他の回答で説明したように、<(cmd)はパイプを作成し、/dev/fd/62コマンドラインに次の内容を入力します。

echo <(true)
  /dev/fd/63

別の代替teeは次の文字列です。

cmd <<<"$text"

Bashが検索可能なtmpファイルを生成し、そのファイルから入力をリダイレクトするようにしたい場合。 (しかし、関数内でstdinをファイルの先頭に巻き戻す方法がわかりません。cat /dev/stdin同じファイルの場所を取得することは可能だと思います。)

答え3

teeファイル(/pipe)を2回読み込むのではなく、使用するように@Peter Cordesの提案を拡張すると、次のように関数を再構築できます。

bugless_part() {
    tee sample.first >sample.second <"$1"
}

として実行すると、bugless_part <(echo "TEST")「TEST」が2つのファイルに保存されます。

関連情報