web-dev-qa-db-ja.com

シェルで、 "2>&1"はどういう意味ですか?

Unixシェルで、さらに操作するためにstderrstdoutstdoutストリームに結合したい場合は、コマンドの最後に次のように追加します。

2>&1

g++からの出力にheadを使用したい場合は、次のようにします。

g++ lots_of_errors 2>&1 | head

だから私は最初のいくつかのエラーだけを見ることができます。

私はいつもこれを思い出すのに苦労しています、そして私は常にそれを調べに行かなければなりません、そしてそれは主に私がこの特定のトリックの構文を完全に理解していないからです。

誰かがこれを分割して2>&1が意味するものを文字ごとに説明することができますか?

1980

ファイル記述子1が標準出力(stdout)です。
ファイル記述子2は標準エラー(stderr)です。

この構文を思い出すための1つの方法があります(完全に正確というわけではありません):最初は、2>1stderrstdoutにリダイレクトするための良い方法のように見えます。ただし、実際には「stderr1という名前のファイルにリダイレクトする」と解釈されます。 &は、それに続くものがファイル記述子であり、ファイル名ではないことを示します。そのため、構文は2>&1になります。

2193
Ayman Hourieh
echo test > afile.txt

stdoutをafile.txtにリダイレクトします。これはすることと同じです

echo test 1> afile.txt

標準エラー出力をリダイレクトするには、次のようにします。

echo test 2> afile.txt

>&は、ストリームを別のファイル記述子にリダイレクトするための構文です。0は標準入力、1は標準出力、2は標準エラー出力です。

次のようにすると、標準出力を標準エラー出力にリダイレクトできます。

echo test 1>&2 # or echo test >&2

またはその逆

echo test 2>&1

つまり、要するに... 2>はstderrを(未指定の)ファイルにリダイレクトし、&1を追加するとstderrをstdoutにリダイレクトします。

553
dbr

リダイレクトに関するいくつかのトリック

これに関するいくつかの構文の特殊性は重要な動作をするかもしれません。リダイレクト、STDERRSTDOUT、およびarguments 順序付け についてのいくつかの小さなサンプルがあります。

1 - 上書きまたは追加

記号>リダイレクトを意味します。

  • >全体として完成したファイルとして送るを意味し、存在する場合はターゲットを上書きします(#3noclobber bash機能を参照)。
  • >>は、に加えて送信が存在する場合、targetに追加されます。

いずれにせよ、ファイルが存在しない場合は作成されます。

2 - シェルコマンドラインは順序に依存します。

これをテストするには、両方の出力に何かを送信する単純なコマンドが必要です。

$ ls -ld /tmp /tnt
ls: cannot access /tnt: No such file or directory
drwxrwxrwt 118 root root 196608 Jan  7 11:49 /tmp

$ ls -ld /tmp /tnt >/dev/null
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt 2>/dev/null
drwxrwxrwt 118 root root 196608 Jan  7 11:49 /tmp

(もちろん/tntという名前のディレクトリはないと期待しています;)まあ、私たちはそれを持っています!

だから、見てみましょう:

$ ls -ld /tmp /tnt >/dev/null
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt >/dev/null 2>&1

$ ls -ld /tmp /tnt 2>&1 >/dev/null
ls: cannot access /tnt: No such file or directory

最後のコマンドラインはSTDERRをコンソールに表示しますが、これは予期された動作ではないようです...しかし...

片方の出力、もう片方、または両方についてポストフィルタリングを作成したい場合は、

$ ls -ld /tmp /tnt | sed 's/^.*$/<-- & --->/'
ls: cannot access /tnt: No such file or directory
<-- drwxrwxrwt 118 root root 196608 Jan  7 12:02 /tmp --->

$ ls -ld /tmp /tnt 2>&1 | sed 's/^.*$/<-- & --->/'
<-- ls: cannot access /tnt: No such file or directory --->
<-- drwxrwxrwt 118 root root 196608 Jan  7 12:02 /tmp --->

$ ls -ld /tmp /tnt >/dev/null | sed 's/^.*$/<-- & --->/'
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt >/dev/null 2>&1 | sed 's/^.*$/<-- & --->/'

$ ls -ld /tmp /tnt 2>&1 >/dev/null | sed 's/^.*$/<-- & --->/'
<-- ls: cannot access /tnt: No such file or directory --->

この段落の最後のコマンド行は、前の段落とまったく同じであることに注意してください。ここで、予想される動作ではないようです(したがって、これは予想される動作になることもあります).

両方の出力で異なる操作をする

$ ( ls -ld /tmp /tnt | sed 's/^/O: /' >&9 ) 9>&2  2>&1  | sed 's/^/E: /'
O: drwxrwxrwt 118 root root 196608 Jan  7 12:13 /tmp
E: ls: cannot access /tnt: No such file or directory

注意:&9記述子は、) 9>&2のために自然に発生します。

補遺:nota! 新しいバージョンの bash>4.0)では、このようなことをするための新機能とよりセクシーな構文があります。

$ ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /')
O: drwxrwxrwt 17 root root 28672 Nov  5 23:00 /tmp
E: ls: cannot access /tnt: No such file or directory

そして最後に、そのようなカスケード出力フォーマットの場合:

$ ((ls -ld /tmp /tnt |sed 's/^/O: /' >&9 ) 2>&1 |sed 's/^/E: /') 9>&1| cat -n
     1  O: drwxrwxrwt 118 root root 196608 Jan  7 12:29 /tmp
     2  E: ls: cannot access /tnt: No such file or directory

補遺:nota! 両方の意味で同じ新しい構文。

$ cat -n <(ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /'))
     1  O: drwxrwxrwt 17 root root 28672 Nov  5 23:00 /tmp
     2  E: ls: cannot access /tnt: No such file or directory

STDOUTが特定のフィルタを通過する場合、STDERRを別のフィルタに通過させ、最後に両方の出力をマージして、3番目のコマンドフィルタを通過させます。

3 - noclobberオプションと>|構文についての一言

それは約 上書き

set -o noclobberはbashに既存のファイルを上書きするのではなく not を上書きするように指示しますが、>|構文を使用するとこの制限を回避できます。

$ testfile=$(mktemp /tmp/testNoClobberDate-XXXXXX)

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:15 CET 2013

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:19 CET 2013

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:21 CET 2013

ファイルは毎回上書きされます。

$ set -o noclobber

$ date > $testfile ; cat $testfile
bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
Mon Jan  7 13:18:21 CET 2013

$ date > $testfile ; cat $testfile
bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
Mon Jan  7 13:18:21 CET 2013

>|でパススルーします。

$ date >| $testfile ; cat $testfile
Mon Jan  7 13:18:58 CET 2013

$ date >| $testfile ; cat $testfile
Mon Jan  7 13:19:01 CET 2013

このオプションの設定を解除するか、すでに設定されている場合は問い合わせます。

$ set -o | grep noclobber
noclobber           on

$ set +o noclobber

$ set -o | grep noclobber
noclobber           off

$ date > $testfile ; cat $testfile
Mon Jan  7 13:24:27 CET 2013

$ rm $testfile

4 - ラストトリックなど.

与えられたコマンドから both 出力をリダイレクトする場合、正しい構文は次のようになります。

$ ls -ld /tmp /tnt >/dev/null 2>&1

このspecialの場合、ショートカット構文があります:&> ...または>&

$ ls -ld /tmp /tnt &>/dev/null

$ ls -ld /tmp /tnt >&/dev/null

注意:2>&1が存在する場合、1>&2も正しい構文です。

$ ls -ld /tmp /tnt 2>/dev/null 1>&2

4b-さて、私はあなたに考えさせます:

$ ls -ld /tmp /tnt 2>&1 1>&2  | sed -e s/^/++/
++/bin/ls: cannot access /tnt: No such file or directory
++drwxrwxrwt 193 root root 196608 Feb  9 11:08 /tmp/

$ ls -ld /tmp /tnt 1>&2 2>&1  | sed -e s/^/++/
/bin/ls: cannot access /tnt: No such file or directory
drwxrwxrwt 193 root root 196608 Feb  9 11:08 /tmp/

4c-興味があるならもっと情報

あなたは打って良いマニュアルを読むことができます:

man -Len -Pless\ +/^REDIRECTION bash

bash console ;-)

291
F. Hauri

私はリダイレクトに関するこの素晴らしい投稿を見つけました:すべてのリダイレクトについて

標準出力と標準エラーの両方をファイルにリダイレクトする

$ command&> file

このワンライナーは、&>演算子を使用して、両方の出力ストリーム(stdoutとstderr)をコマンドからファイルにリダイレクトします。これは、両方のストリームを同じ宛先にすばやくリダイレ​​クトするためのBashのショートカットです。

Bashが両方のストリームをリダイレクトした後のファイル記述子テーブルは次のようになります。

Enter image description here

ご覧のとおり、stdoutとstderrはどちらもfileを指しています。そのため、stdoutとstderrに書き込まれたものはすべてfileに書き込まれます。

両方のストリームを同じ宛先にリダイレクトする方法はいくつかあります。各ストリームを次々にリダイレクトできます。

$ command>ファイル2>&1

これは、両方のストリームをファイルにリダイレクトするためのはるかに一般的な方法です。最初のstdoutはfileにリダイレクトされ、次にstderrはstdoutと同じものになるように複製されます。そのため、どちらのストリームもfileを指すことになります。

Bashがいくつかのリダイレクトを見たとき、それは左から右へそれらを処理します。手順を見て、それがどのように起こるかを見てみましょう。コマンドを実行する前は、Bashのファイル記述子テーブルは次のようになっています。

Enter image description here

Bashは最初のリダイレクトファイルを処理します。これまでに見たことがあるので、標準出力をファイルに指定します。

Enter image description here

次のBashは2番目のリダイレクト2>&1を見ています。これまでにこのリダイレクトを見たことはありません。これはファイルディスクリプタ2をファイルディスクリプタ1のコピーに複製します。

Enter image description here

両方のストリームはファイルにリダイレクトされています。

しかし注意してください。書き込み

コマンド>ファイル2>&1

書くことと同じではありません:

$ command 2>&1>ファイル

Bashではリダイレクトの順序が重要です。このコマンドは、標準出力のみをファイルにリダイレクトします。標準エラー出力は依然として端末に印刷されます。なぜそれが起こるのか理解するために、もう一度ステップを通過しましょう。そのため、コマンドを実行する前は、ファイル記述子テーブルは次のようになります。

Enter image description here

Bashはリダイレクトを左から右に処理するようになりました。最初は2>&1を見ているので、stderrをstdoutに複製します。ファイル記述子テーブルは次のようになります。

Enter image description here

これでBashは2番目のリダイレクト>fileを見て、標準出力をファイルにリダイレクトします。

Enter image description here

ここで何が起こるかわかりますか?標準出力はファイルを指しますが、標準エラー出力はまだ端末を指しています。標準エラー出力に書き込まれたものはすべて画面に出力されます。そのため、リダイレクトの順序には非常に注意してください。

また、Bashでは、

$ command&> file

まったく同じです。

$ command>&file

79
Deen John

番号はファイル記述子(fd)を表します。

  • ゼロはstdinです
  • 一つはstdoutです
  • 2つはstderrです

2>&1はfd 2を1にリダイレクトします。

プログラムが使用する場合、これは任意の数のファイル記述子に対して機能します。

忘れてしまったら/usr/include/unistd.hを見てください。

/* Standard file descriptors.  */
#define STDIN_FILENO    0   /* Standard input.  */
#define STDOUT_FILENO   1   /* Standard output.  */
#define STDERR_FILENO   2   /* Standard error output.  */

それは私がカスタムロギングのために非標準のファイルディスクリプタを使うCツールを書いたので、あなたがそれをファイルか何かにリダイレクトしない限りあなたはそれを見ない。

77
Colin Burnett

その構文は標準エラーストリーム(stderr)を標準出力の現在の場所(stdout)に送ります - この通貨の問題は他の答えでは無視されていたようです。

このメソッドを使用すると、任意の出力ハンドルを別の出力ハンドルにリダイレクトできますが、処理のためにstdoutストリームとstderrストリームを単一のストリームにチャネル化するためによく使用されます。

例をいくつか示します。

# Look for ERROR string in both stdout and stderr.
foo 2>&1 | grep ERROR

# Run the less pager without stderr screwing up the output.
foo 2>&1 | less

# Send stdout/err to file (with append) and terminal.
foo 2>&1 |tee /dev/tty >>outfile

# Send stderr to normal location and stdout to file.
foo >outfile1 2>&1 >outfile2

最後のものはnotstderroutfile2に導くことに注意してください - それはstdoutが引数に遭遇した時のものにリダイレクトし(outfile1)そしてthenstdoutoutfile2にリダイレクトします。

これはかなり洗練されたトリックを可能にします。

54
paxdiablo

2>&1はPOSIXシェルの構成体です。トークンごとの内訳は次のとおりです。


2: " 標準エラー "出力ファイルディスクリプタ。

>& 出力ファイル記述子 operatorを複製します( 出力のリダイレクト operator >の変形)。 [x]>&[y]が与えられると、xで示されるファイル記述子は、出力ファイル記述子yのコピーになります。

1 " 標準出力 "出力ファイルディスクリプタ。

2>&1は、ファイル記述子1をロケーション2にコピーするので、実行環境で2( "標準エラー")に書き込まれた出力は、元々1( "標準出力")で記述されたのと同じファイルに送られます。


さらなる説明:

ファイル記述子 : "ファイルアクセスの目的で開いているファイルを識別するために使用されるプロセスごとの一意の負でない整数。"

標準出力/ error :シェルの資料の リダイレクト セクションにある以下の注を参照してください。

開いているファイルは、ゼロから始まる10進数で表されます。可能な最大の値は実装定義です。しかしながら、すべての実装はアプリケーションによる使用のために少なくとも0から9までをサポートしなければならない。これらの番号は「ファイル記述子」と呼ばれます。値0、1、および2は特別な意味と従来の使用法を持ち、特定のリダイレクト操作によって暗黙的に示されます。それらはそれぞれ標準入力、標準出力、および標準エラーと呼ばれます。プログラムは通常、標準入力から入力を受け取り、標準出力に出力を書き込みます。エラーメッセージは通常標準エラーで書かれています。ファイル記述子番号を指定するために、リダイレクト演算子の前に1つ以上の数字を入れることができます(間に文字を入れることはできません)。

17
wjordan

2はコンソールの標準エラーです。

1はコンソールの標準出力です。

これは標準のUnixであり、WindowsもPOSIXに準拠しています。

例えば。走ったとき

Perl test.pl 2>&1

標準エラーは標準出力にリダイレクトされるので、両方の出力を一緒に見ることができます。

Perl test.pl > debug.log 2>&1

実行後、エラーを含むすべての出力がdebug.logに表示されます。

Perl test.pl 1>out.log 2>err.log

標準出力はout.logに、標準エラー出力はerr.logに出力されます。

これらを理解しようとすることをお勧めします。

17
Marcus Thornton

あなたの質問に答えるには:これはエラー出力(通常はstderrに送られる)を取り、それを標準出力(stdout)に書き込みます。

あなたがすべての出力のためにページングを必要とするとき、これは例えば 'more'と共に役に立ちます。使用情報を標準エラー出力に出力するようなプログラムもあります。

覚えやすくするために

  • 1 =標準出力(プログラムは通常の出力を印刷します)
  • 2 =標準エラー(プログラムがエラーを表示する場合)

"2>&1"は単に標準エラー出力に、標準出力に送られるすべてを指します。

私はまた読むことをお勧めします エラーのリダイレクトに関するこの投稿 この問題の詳細な説明はここで説明します。

16
Andrioid

プログラマの観点からすると、これは正確には次のことを意味します。

dup2(1, 2);

manページ を参照してください。

2>&1 copy であることを理解していることも理由を説明しています...

command >file 2>&1

...は...と同じではありません.

command 2>&1 >file

最初のものは両方のストリームをfileに送り、2番目のものはエラーをstdoutに送り、通常の出力をfileに送ります。

11
ams

/fooがあなたのシステムに存在せず、/tmpが存在しなければ…

$ ls -l /tmp /foo

/tmpの内容を表示し、/fooのエラーメッセージを表示します。

$ ls -l /tmp /foo > /dev/null

/tmpの内容を/dev/nullに送り、/fooのエラーメッセージを表示します。

$ ls -l /tmp /foo 1> /dev/null

全く同じことをします( 1 に注意してください)

$ ls -l /tmp /foo 2> /dev/null

/tmpの内容を表示し、エラーメッセージを/dev/nullに送信します。

$ ls -l /tmp /foo 1> /dev/null 2> /dev/null

リストとエラーメッセージの両方を/dev/nullに送信します。

$ ls -l /tmp /foo > /dev/null 2> &1

速記です

6
Matijs

人々は、常にpaxdiabloのリダイレクトターゲットのcurrentロケーションに関するヒントを思い出してください...それ重要。

2>&1演算子の個人用ニーモニックは次のとおりです。

  • &'and'または'add'を意味すると考えてください(文字はampers-and、そうではありませんか?)
  • したがって、次のようになります: '2(stderr)を1(stdout)がすでに/現在の場所にリダイレクトし、add両方のストリーム'

同じニーモニックは、他の頻繁に使用されるリダイレクト1>&2でも機能します:

  • &の意味はandまたはaddを意味します...(アンパサンドについての考えはわかりますか?)
  • したがって、次のようになります: '1(stdout)を2(stderr)already/currently is and add both streams'(

そして、常に覚えておいてください:リダイレクトのチェーンを「最後から」、右から左に読む必要があります(not左から右)。

6
Kurt Pfeifle

これは、エラーを標準出力または端末に渡すのと同じです。

つまり、cmdはコマンドではありません。

$cmd 2>filename
cat filename

command not found

エラーはこのようにファイルに送信されます。

2>&1

標準エラーが端末に送信されます。

5
Kalanidhi

入力をリダイレクトする

入力をリダイレクトすると、Wordの展開に由来する名前のファイルがファイル記述子n、またはnが指定されていない場合は標準入力(ファイル記述子0)の読み取り用に開かれます。

入力をリダイレクトするための一般的な形式は次のとおりです。

[n]<Word

出力をリダイレクトする

出力をリダイレクトすると、Wordの展開に由来する名前のファイルがファイル記述子nへの書き込み用に開かれます。nが指定されていない場合は標準出力(ファイル記述子1)になります。ファイルが存在しない場合は作成されます。存在する場合は、ゼロサイズに切り捨てられます。

出力をリダイレクトするための一般的な形式は次のとおりです。

[n]>Word

ファイルディスクリプタの移動

リダイレクト演算子

[n]<&digit-

ファイル記述子の桁をファイル記述子nに移動します。nが指定されていない場合は標準入力(ファイル記述子0)に移動します。 digitは、nと重複した後に閉じられます。

同様に、リダイレクト演算子

[n]>&digit-

ファイル記述子の桁をファイル記述子nに移動します。nが指定されていない場合は、標準出力(ファイル記述子1)に移動します。

参照:

man bash

redirectionセクションを見つけるために/^REDIRECTを入力してください。

オンライン版はこちら:3.6リダイレクト

シモンズ:

多くの場合、manはLinuxを学ぶための強力なツールでした。

4
yurenchen

入力は0、標準出力は1、標準エラー出力は2です。

1つのヒント somecmd >1.txt 2>&1は正しいのに対し、somecmd 2>&1 >1.txtは完全に 間違った ですが、効果はありません。

1
fzyzcjy