bash スクリプトはパイプライン内から標準出力を書き込むにはどうすればよいですか?

bash スクリプトはパイプライン内から標準出力を書き込むにはどうすればよいですか?

関数を呼び出す bash スクリプトがあります。関数は、とりわけ、その出力をシンクするパイプラインを実行します。これを単純化するために、以下に例を示します。

#!/bin/bash
func() {
  ls "$@" | sort | rev > /tmp/output
}
func "$@"

次に、次のように実行します。 必要な処理が実行され、ペイロードがファイルに配信されます。 画面には出力されません。

$ ./myscript .

さて、 を標準出力に出力したいとしますsort。どうすればよいでしょうか?

次のようにして実現できます:

ls "$@" | sort | tee /dev/tty | rev > /tmp/output

ただし、/dev/ttyこれは機能しないため、使用するのは間違いです。

$ ./myscript > myfile

関数内のパイプライン内から bash スクリプトの標準出力を参照するより正確な方法はありますか?

(私はArch Linuxでbash 4.3.0を使用しています)

答え1

私が考えられる最も簡単な方法は次のとおりです。

ls "$@" | sort | tee >(rev > /tmp/output)

tee1 つのコピーを STDOUT に送信します。その後に がなくなったため|、これが継承され、リダイレクトされていない場合は TTY に、リダイレクトされてmyfileいる場合は
に送信されます。もう 1 つのコピーは、rev > /tmp/outputその STDIN に送信されます。bash では、>(...)括弧内の内容を実行し、 を>(...)その STDIN に接続されたパイプへのパスに置き換えます。

答え2

他の答えはこれについて明確ではないので、他の(別の)方法は

exec 3>&1
ls | sort | tee /dev/fd/3 | rev > /tmp/output

exec 3>&1 重複ファイル記述子 1 (stdout) をファイル記述子 3 として複製します。次に、の出力tee /dev/fd/3のコピーをsortそのファイル記述子に書き込みます。これはどのシェルでも動作するはずですが、オペレーティング システムに依存する可能性があります。OS に依存しないが、 固有のバリアントはbash次のとおりです。

exec 3>&1
ls | sort | tee >( cat >&3 ) | rev > /tmp/output

ではbash、実行中のプロセスへのパイプへのファイルハンドルを提供します。>(command)command任意の(?)シェルで、command >&fdcommand stdout は指定されたファイル記述子にリダイレクトされます。このファイル記述子は事前に確立されている必要があります。

より複雑なバージョンは、どの*nix (Posix)システムでも動作するはずですが、

pipe_to_stdout=$(mktemp -u)
mkfifo "$pipe_to_stdout"
cat "$pipe_to_stdout" &
ls | sort | tee "$pipe_to_stdout" | rev > /tmp/output
rm "$pipe_to_stdout"

catこれは 2 番目の例 ( FIFO から読み取り、stdout に書き込む)とほぼ同じですが、シェル レベルでの煙と鏡の使用が少なくなります。

これらの回答は柔軟性があり、コマンドを並べ替えるだけで出力をls標準出力に書き込むことができることに注意してください。

関連情報