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)

teeコピーはSTDOUTに転送され、その後にaがなくなったため、|これが継承されます。つまり、リダイレクトがない場合はTTYに移動し、myfileそうであればTTYに移動します。別のコピーが対応するSTDIN
に送信されます。rev > /tmp/outputBashでは、>(...)括弧の間のすべてのエントリが実行され、>(...)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独立でなければなりませんが、bashOSに固有のバリエーションは次のとおりです。

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

bash、実行中のプロセスのパイプを指すファイルハンドルを提供します。>(command)command。どの (?) シェルで次を実行します。command >&fdcommand 標準出力は、以前に設定されている必要がある指定されたファイル記述子にリダイレクトされます。

すべての*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"

これは2番目の例(fifoで読み込んでstdoutに書き込む)とほぼ同じですcatが、シェルレベルでは煙とミラーが少なくなります。

lsこれらの答えは、出力を標準出力に書き込むようにコマンドを簡単に並べ替えることができるという点で柔軟です。

関連情報