Unixシェルで、さらに操作するためにstderr
とstdout
をstdout
ストリームに結合したい場合は、コマンドの最後に次のように追加します。
2>&1
g++
からの出力にhead
を使用したい場合は、次のようにします。
g++ lots_of_errors 2>&1 | head
だから私は最初のいくつかのエラーだけを見ることができます。
私はいつもこれを思い出すのに苦労しています、そして私は常にそれを調べに行かなければなりません、そしてそれは主に私がこの特定のトリックの構文を完全に理解していないからです。
誰かがこれを分割して2>&1
が意味するものを文字ごとに説明することができますか?
ファイル記述子1が標準出力(stdout
)です。
ファイル記述子2は標準エラー(stderr
)です。
この構文を思い出すための1つの方法があります(完全に正確というわけではありません):最初は、2>1
はstderr
をstdout
にリダイレクトするための良い方法のように見えます。ただし、実際には「stderr
を1
という名前のファイルにリダイレクトする」と解釈されます。 &
は、それに続くものがファイル記述子であり、ファイル名ではないことを示します。そのため、構文は2>&1
になります。
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にリダイレクトします。
これに関するいくつかの構文の特殊性は重要な動作をするかもしれません。リダイレクト、STDERR
、STDOUT
、およびarguments 順序付け についてのいくつかの小さなサンプルがあります。
記号>
はリダイレクトを意味します。
>
は全体として完成したファイルとして送るを意味し、存在する場合はターゲットを上書きします(#3のnoclobber
bash機能を参照)。>>
は、に加えて送信が存在する場合、targetに追加されます。いずれにせよ、ファイルが存在しない場合は作成されます。
これをテストするには、両方の出力に何かを送信する単純なコマンドが必要です。
$ 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番目のコマンドフィルタを通過させます。
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
与えられたコマンドから 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
$ 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/
あなたは打って良いマニュアルを読むことができます:
man -Len -Pless\ +/^REDIRECTION bash
bash console ;-)
私はリダイレクトに関するこの素晴らしい投稿を見つけました:すべてのリダイレクトについて
標準出力と標準エラーの両方をファイルにリダイレクトする
$ command&> file
このワンライナーは、&>
演算子を使用して、両方の出力ストリーム(stdoutとstderr)をコマンドからファイルにリダイレクトします。これは、両方のストリームを同じ宛先にすばやくリダイレクトするためのBashのショートカットです。
Bashが両方のストリームをリダイレクトした後のファイル記述子テーブルは次のようになります。
ご覧のとおり、stdoutとstderrはどちらもfile
を指しています。そのため、stdoutとstderrに書き込まれたものはすべてfile
に書き込まれます。
両方のストリームを同じ宛先にリダイレクトする方法はいくつかあります。各ストリームを次々にリダイレクトできます。
$ command>ファイル2>&1
これは、両方のストリームをファイルにリダイレクトするためのはるかに一般的な方法です。最初のstdoutはfileにリダイレクトされ、次にstderrはstdoutと同じものになるように複製されます。そのため、どちらのストリームもfile
を指すことになります。
Bashがいくつかのリダイレクトを見たとき、それは左から右へそれらを処理します。手順を見て、それがどのように起こるかを見てみましょう。コマンドを実行する前は、Bashのファイル記述子テーブルは次のようになっています。
Bashは最初のリダイレクトファイルを処理します。これまでに見たことがあるので、標準出力をファイルに指定します。
次のBashは2番目のリダイレクト2>&1を見ています。これまでにこのリダイレクトを見たことはありません。これはファイルディスクリプタ2をファイルディスクリプタ1のコピーに複製します。
両方のストリームはファイルにリダイレクトされています。
しかし注意してください。書き込み
コマンド>ファイル2>&1
書くことと同じではありません:
$ command 2>&1>ファイル
Bashではリダイレクトの順序が重要です。このコマンドは、標準出力のみをファイルにリダイレクトします。標準エラー出力は依然として端末に印刷されます。なぜそれが起こるのか理解するために、もう一度ステップを通過しましょう。そのため、コマンドを実行する前は、ファイル記述子テーブルは次のようになります。
Bashはリダイレクトを左から右に処理するようになりました。最初は2>&1を見ているので、stderrをstdoutに複製します。ファイル記述子テーブルは次のようになります。
これでBashは2番目のリダイレクト>file
を見て、標準出力をファイルにリダイレクトします。
ここで何が起こるかわかりますか?標準出力はファイルを指しますが、標準エラー出力はまだ端末を指しています。標準エラー出力に書き込まれたものはすべて画面に出力されます。そのため、リダイレクトの順序には非常に注意してください。
また、Bashでは、
$ command&> file
まったく同じです。
$ command>&file
番号はファイル記述子(fd)を表します。
stdin
ですstdout
です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ツールを書いたので、あなたがそれをファイルか何かにリダイレクトしない限りあなたはそれを見ない。
その構文は標準エラーストリーム(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
最後のものはnotstderr
をoutfile2
に導くことに注意してください - それはstdout
が引数に遭遇した時のものにリダイレクトし(outfile1
)そしてthenはstdout
をoutfile2
にリダイレクトします。
これはかなり洗練されたトリックを可能にします。
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つ以上の数字を入れることができます(間に文字を入れることはできません)。
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に出力されます。
これらを理解しようとすることをお勧めします。
あなたの質問に答えるには:これはエラー出力(通常はstderrに送られる)を取り、それを標準出力(stdout)に書き込みます。
あなたがすべての出力のためにページングを必要とするとき、これは例えば 'more'と共に役に立ちます。使用情報を標準エラー出力に出力するようなプログラムもあります。
覚えやすくするために
"2>&1"は単に標準エラー出力に、標準出力に送られるすべてを指します。
私はまた読むことをお勧めします エラーのリダイレクトに関するこの投稿 この問題の詳細な説明はここで説明します。
プログラマの観点からすると、これは正確には次のことを意味します。
dup2(1, 2);
manページ を参照してください。
2>&1
が copy であることを理解していることも理由を説明しています...
command >file 2>&1
...は...と同じではありません.
command 2>&1 >file
最初のものは両方のストリームをfile
に送り、2番目のものはエラーをstdout
に送り、通常の出力をfile
に送ります。
/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
速記です
人々は、常に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左から右)。
これは、エラーを標準出力または端末に渡すのと同じです。
つまり、cmd
はコマンドではありません。
$cmd 2>filename
cat filename
command not found
エラーはこのようにファイルに送信されます。
2>&1
標準エラーが端末に送信されます。
入力をリダイレクトする
入力をリダイレクトすると、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を学ぶための強力なツールでした。
入力は0、標準出力は1、標準エラー出力は2です。
1つのヒント :somecmd >1.txt 2>&1
は正しいのに対し、somecmd 2>&1 >1.txt
は完全に 間違った ですが、効果はありません。