このコマンドのリダイレクトを理解していますか? [コピー]

このコマンドのリダイレクトを理解していますか? [コピー]

魔法の命令を見つけました。ここ

./my.sh 3>all 1> >(tee out >&3) 2> >(tee err >&3)

私が混乱している場所があります。

  1. 3>allfileにファイル記述子3を設定することを意味しますかall
  2. 何をすべき1> >ですか2> >?私の理解によると、コマンドはでなければなりませ./my.sh 3>all 1>(tee out >&3) 2>(tee err >&3)んが、うまくいきません。
  3. (tee err >&3)ファイルを上書きしないのはなぜですかall

これは私のものです。my.sh

#!/bin/bash

echo myecho
ls dflj

答え1

Bashのマニュアルページでこの構文を読むことができます。プロセスの置き換え:

>(list)。プロセスリスト実行されると、その出力は/ dev / fdのファイルにリンクされます。ファイル名は、拡張結果として現在のコマンドに引数として渡されます。

このコマンドの出力を見ると、リダイレクトは行われません。

echo >(echo hi >/tmp/a) >(echo lo >/tmp/b)

それは(私のシステムで):

/dev/fd/63 /dev/fd/62

したがって、and1> >(...)で読む必要があります。 2番目の部分はで置き換えられ、次にstdoutをファイル記述子63にリダイレクトします。 1>>(...)/dev/fd/631> /dev/fd/63

bashは別のプロセスでコマンドを実行し、>(...)そのプロセスの標準入力をファイル記述子63に接続します。次の例を確認してください。

set -x
echo hello > >(cat -n)

Echoの標準出力は入力として接続され、次のようになりcat -nます。

+ echo hello
++ cat -n
 1  hello

おそらくあなたが逃しているのはファイル記述子(fd)がファイルの場合クロスプロセス(bashが使用するプロセス>(...))を使用すると、新しいプロセスから同じfdを継承できます。したがって、これら2つのプロセスは同じfdを共有します。それにちょうど一つあります。ファイルオフセットfdの場合、プロセス1がfdに3文字を書き込むと、オフセットは0から3に移動します。プロセス2がfdに5文字を書き込むと、データはオフセット3に配置され、オフセットは8になります。プロセス2 1が別の文字を書き込むと、オフセット8に配置されます。これは、あなたの質問のtee2つのコマンドがall互いに上書きせずに同じファイルに書き込む方法です。

を使用すると、>&3新しいfdは生成されません。単に現在のstdout fd 1を閉じてから、fd 3の番号をfd 1に戻します。したがって、各プロセスに異なる数字が表示されていても(man dup2基本システムコールを参照)、両方のプロセスに対してまだ1つのfdしかありません。

答え2

meuhの優れた理論的答えよりも文字通り説明しようとすると、おそらく知っているように、基本的なファイル記述子がたくさんあります。

  • 0標準入力を意味します。
  • 1標準出力を意味します。
  • 2標準エラーを示します。

コマンドは次のことを行います。

  • 3>allファイルを指す新しいファイル記述子を開きます。all
  • 1> >(tee out >&3)meuhが説明したように、stdout(1)をteeコマンドによって開き、返されたファイル記述子にリダイレクトします。
    • tee out >&3入力(この場合はスクリプトの標準出力)をoutという名前のファイルにリダイレクトし、3ファイル記述子が指す場所(この場合はすべてファイル)
  • 2> >(tee err >&3)meuhが説明したように、stderr(2)をteeコマンドによって開き、返されたファイル記述子にリダイレクトします。
    • tee err >&3入力(この場合はスクリプトのstderr)をerrというファイルにリダイレクトし、3ファイル記述子が指す場所(この場合はファイルall)

>>あなたの意見を見ると、混乱しているのは、出力をファイルに追加したい場合は、リダイレクト演算子を使用する必要があることです。

ここではそうではありません。実際に行うことは、stdoutとstderrをファイルallを指すファイル記述子にリンクすることだけです。

効果は次のとおりです。

./my.sh > all 2>&1

まず、stdoutをallファイルにリダイレクトし、次にstderrをstdoutが指す場所にリダイレクトします。

関連情報