web-dev-qa-db-ja.com

出力リダイレクトの順序を理解する方法は?

だから、標準出力と標準エラーをさまざまな領域に渡す方法を学ぼうとしています。

here.txtだけのフォルダがあるとします。

だから

ls here.txt not-here.txt  1>out  2>&1

here.txtが存在するため、ファイルoutに送信する出力がいくつかありますが、not-here.txtが存在しないため、標準エラーを介してエラーが送信されます。 2>&1で出力します。

しかし、なぜこれが機能しないのですか:

ls here.txt not-here.txt 2>&1 1>out

標準出力命令の後にリダイレクトを行う場合にのみ機能するようです?どうして?

10
AJJ

リダイレクトの順序は重要です。たとえば、コマンド

ls > dirlist 2>&1

コマンドが標準出力と標準エラーの両方をファイルdirlistに送信します

ls 2>&1 > dirlist

標準出力がdirlistにリダイレクトされる前に標準出力が標準出力から複製されたため(通常はターミナルウィンドウを指しているため)、標準出力のみをファイルdirlistに送信します。

最初はこれは直観に反すると感じるかもしれませんが、それについて考えた後、私たちはそれを理解することができます。


この説明は、リダイレクトに関する章のman bashにあります。

リダイレクション

コマンドを実行する前に、シェルによって解釈される特別な表記法を使用して、コマンドの入力と出力をリダイレクトできます。リダイレクションを使用すると、コマンドファイルハンドルを複製、開く、閉じる、別のファイルを参照することができ、コマンドが読み書きするファイルを変更できます。リダイレクトは、現在のシェル実行環境でファイルハンドルを変更するためにも使用できます。次のリダイレクト演算子は、単純なコマンド内の任意の場所に先行するか表示されるか、コマンドの後に続く場合があります。リダイレクトは、左から右に表示される順序で処理されます。

ファイル記述子番号が前に付く場合がある各リダイレクトは、代わりに{varname}という形式のWordが前に付く場合があります。この場合、>&-および<&-を除く各リダイレクト演算子に対して、シェルは10以上のファイル記述子を割り当て、varnameに割り当てます。 >&-または<&-の前に{varname}が付いている場合、varnameの値は閉じるファイル記述子を定義します。

以下の説明では、ファイル記述子番号が省略され、リダイレクト演算子の最初の文字が<である場合、リダイレクトは標準入力(ファイル記述子0)を参照します。リダイレクト演算子の最初の文字が>の場合、リダイレクトは標準出力(ファイル記述子1)を参照します。

以下の説明でリダイレクト演算子に続くWordは、特に明記しない限り、ブレース展開、チルダ展開、パラメータおよび変数展開、コマンド置換、算術展開、引用除去、パス名展開、およびワード分割の対象です。 bashが複数のWordに展開されると、bashはエラーを報告します。

リダイレクトの順序は重要であることに注意してください。たとえば、コマンド

ls > dirlist 2>&1

コマンドの実行中に、標準出力と標準エラーの両方をファイルdirlistに送信します

ls 2>&1 > dirlist

標準出力がdirlistにリダイレクトされる前に標準エラーが標準出力から複製されたため、標準出力のみをファイルdirlistに送信します。

編集:次のコマンドラインは何が起こるかを説明するかもしれません

準備する

sudodus@xenial32:~$ touch qwerty;rm asdf
rm: cannot remove 'asdf': No such file or directory

1つの既存のファイルと1つの存在しないファイルに対してlistコマンドを実行します

sudodus@xenial32:~$ ls qwerty asdf
ls: cannot access 'asdf': No such file or directory
qwerty

標準出力をリダイレクトする前に、エラー出力をリダイレクトします。標準出力のみが出力ファイルにリダイレクトされます。

sudodus@xenial32:~$ ls qwerty asdf 2>&1 > output-file ;echo '---';cat output-file 
ls: cannot access 'asdf': No such file or directory
---
qwerty

標準出力をリダイレクトした後、エラー出力をリダイレクトします。エラー出力と標準出力の両方が出力ファイルにリダイレクトされます。

sudodus@xenial32:~$ ls qwerty asdf > output-file 2>&1 ;echo '---';cat output-file
---
ls: cannot access 'asdf': No such file or directory
qwerty

トークン&>を使用して、標準エラーと標準出力の両方をリダイレクトできます。 bashで使用できますが、他のシェルでは使用できない場合があります。

sudodus@xenial32:~$ ls qwerty asdf &> output-file ;echo '---';cat output-file
---
ls: cannot access 'asdf': No such file or directory
qwerty
sudodus@xenial32:~$ 
5
sudodus
  • 2>xは、ファイル名xが記述子に書き込まれたデータを受け取ることを意味します2(stderr、標準エラーとも呼ばれます)
  • ...しかし、x&1として指定されている場合、「常に1に続く」という意味ではありません。 "1の現在のプロパティをコピーする(そしてそのままにしておく)"を意味します。
  • リダイレクトは、コマンドラインで入力した順序と同じ順序で適用されますが、実際に実行される前です。

これが2>&1 1>whateverがstderrを端末に出力する理由です。

これがfind / -name mylostfile.txt 3>&1 1>&2 2>&3 | grep -v 'Permission denied'がstderrとstderrを交換する理由です。これにより、いくつかの一般的なstderr行をフィルターに掛けることができますが、すべてのstdoutが表示されます。 (ここでの記述子3は、プログラムでは使用されません)。

3
kubanczyk

シェルは、物を見る順序で出会い、設定します。最初の場合:

ls here.txt not-here.txt  1>out  2>&1

出力はリダイレクトされ、標準エラーが同じ場所に送信されます。

2番目の場合、

ls here.txt not-here.txt 2>&1 1>out

標準出力は引き続き端末に設定されるため、標準エラーが端末に送信され、標準出力が変更されます。シェルはすでに標準エラーを設定しています。

2
jpezz