シェルでは、「 2>&1 」は何を意味しますか?
質問
Unix シェルで結合したい場合 stderr
そして stdout
に stdout
ストリームをさらに操作するには、コマンドの最後に次のコードを追加します。
2>&1
それで、私が使用したい場合は、 head
からの出力について g++
, 、次のようなことができます。
g++ lots_of_errors 2>&1 | head
したがって、最初のいくつかのエラーのみが表示されます。
私はいつもこれを思い出すのに苦労し、常に調べなければなりません。主な理由は、この特定のトリックの構文を完全に理解していないからです。
誰かこれを分解して、1文字ずつ説明してもらえませんか 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
stderrをリダイレクトするには、次のようにします。
echo test 2> afile.txt
>&
は、ストリームを別のファイル記述子にリダイレクトする構文です。0は標準入力、1は標準出力、2は標準エラーです。
次のようにして、stdoutをstderrにリダイレクトできます。
echo test 1>&2 # or echo test >&2
またはその逆:
echo test 2>&1
したがって、要するに... 2>
はstderrを(指定されていない)ファイルにリダイレクトし、& 1
を追加するとstderrがstdoutにリダイレクトされます。
リダイレクトに関するいくつかのトリック
これに関する構文の特殊性によっては、重要な動作が発生する可能性があります。リダイレクトに関する小さなサンプルがいくつかあります。 STDERR
, STDOUT
, 、および引数 注文する.
1 - 上書きまたは追加しますか?
シンボル >
平均 リダイレクション.
>
平均 完成したファイル全体として送信, 、ターゲットが存在する場合は上書きします(「noclobber
bash 機能 #3 後で)。>>
平均 に加えて送信します ターゲットが存在する場合はターゲットに追加されます。
いずれの場合も、ファイルが存在しない場合は作成されます。
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
.
補遺:ノータ! 新しいバージョンでは、 バッシュ (>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
補遺:ノータ! どちらの方法でも同じ新しい構文:
$ 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に指示する ない 既存のファイルを上書きします。 >|
構文を使用すると、この制限を回避できます。
$ 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 - 最後のトリックとその他...
リダイレクト用 両方 特定のコマンドからの出力を確認すると、正しい構文は次のとおりであることがわかります。
$ ls -ld /tmp /tnt >/dev/null 2>&1
このために 特別 この場合、ショートカット構文があります。 &>
...または >&
$ 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
で バッシュ コンソール ;-)
リダイレクトに関するこの素晴らしい投稿を見つけました。 リダイレクトについて
標準出力と標準エラーの両方をファイルにリダイレクトします
$コマンド&>ファイル
このワンライナーでは、 &>
オペレータを使用して、両方の出力ストリーム (stdout と stderr) をコマンドからファイルにリダイレクトします。これは、両方のストリームを同じ宛先にすばやくリダイレクトするための Bash のショートカットです。
Bash が両方のストリームをリダイレクトした後のファイル記述子テーブルは次のようになります。
ご覧のとおり、stdout と stderr の両方が次を指しています。 file
. 。したがって、stdout と stderr に書き込まれたものはすべて書き込まれます。 file
.
両方のストリームを同じ宛先にリダイレクトする方法はいくつかあります。各ストリームを次々にリダイレクトできます。
$ コマンド >ファイル 2>&1
これは、両方のストリームをファイルにリダイレクトする、より一般的な方法です。最初に stdout がファイルにリダイレクトされ、次に stderr が stdout と同じになるように複製されます。したがって、両方のストリームは最終的に次のことを指します file
.
Bash は複数のリダイレクトを検出すると、それらを左から右に処理します。手順を進めて、それがどのように起こるかを見てみましょう。コマンドを実行する前、Bash のファイル記述子テーブルは次のようになります。
ここで、Bash は最初のリダイレクト ファイルを処理します。これは前にも見たことがありますが、stdout がファイルを指すようになります。
次に Bash は 2 番目のリダイレクト 2>&1 を認識します。このリダイレクトはこれまで見たことがありません。これは、ファイル記述子 2 を複製してファイル記述子 1 のコピーにし、次のようになります。
両方のストリームがファイルにリダイレクトされました。
ただし、ここで注意してください!書き込み
コマンド >ファイル 2>&1
これは次のように書くことと同じではありません:
$ コマンド 2>&1 >ファイル
Bash ではリダイレクトの順序が重要です。このコマンドは、標準出力のみをファイルにリダイレクトします。標準エラー出力は引き続き端末に出力されます。なぜそうなるのかを理解するために、手順をもう一度見てみましょう。したがって、コマンドを実行する前のファイル記述子テーブルは次のようになります。
Bash は左から右へのリダイレクトを処理するようになりました。最初に 2>&1 が認識されるため、stderr が stdout に複製されます。ファイル記述子テーブルは次のようになります。
ここで、Bash は 2 番目のリダイレクトを認識します。 >file
, そして、標準出力を次のファイルにリダイレクトします。
ここで何が起こるかわかりますか?Stdout はファイルを指すようになりましたが、stderr は依然としてターミナルを指します。標準エラー出力に書き込まれたものはすべて画面に出力されます。したがって、リダイレクトの順序には非常に注意してください。
また、Bash では次のように書くことにも注意してください。
$コマンド&>ファイル
は次とまったく同じです:
$コマンド>ファイル(&F)
数字はファイル記述子(fd)を示します。
- ゼロは
stdin
- 1つは
stdout
です
- 2つは
stderr
です
2&gt;&amp; 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
)の current の場所に送信します-この通貨の問題は他の回答では無視されています。
このメソッドを使用すると、出力ハンドルを別の出力ハンドルにリダイレクトできますが、最もよく使用されるのは、 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
最後のものは、 stderr
を outfile2
にリダイレクトしない ことに注意してください- stdout
にリダイレクトします引数が見つかったとき( outfile1
)、 then は stdout
を outfile2
にリダイレクトします。
これにより、かなり洗練されたトリックが可能になります。
2&gt;&amp; 1
はPOSIXシェル構成です。トークンごとの内訳は次のとおりです。
2
:&quot; 標準エラー&quot;出力ファイル記述子。
&gt;&amp;
: 出力ファイル記述子の複製 演算子( 出力リダイレクト 演算子&gt;
)。 [x]&gt;&amp; [y]
の場合、 x
で示されるファイル記述子は、出力ファイル記述子 y
。
1
&quot; 標準出力&quot;出力ファイル記述子。
式 2&gt;&amp; 1
は、ファイル記述子 1
を場所 2
にコピーするため、出力は 2 実行環境内のcode>(「標準エラー」)は、元々
1
(&quot;標準出力&quot;)で記述された同じファイルに移動します。
詳細説明:
ファイル記述子 : &quot;ファイルアクセスのために開いているファイルを識別するために使用される、プロセスごとの一意の負でない整数。
標準出力/エラー:リダイレクトセクション:
開いているファイルは、ゼロで始まる10進数で表されます。可能な最大値は実装定義です。ただし、すべての実装は、アプリケーションで使用するために、少なくとも0〜9をサポートする必要があります。これらの番号は「ファイル記述子」と呼ばれます。値0、1、および2は、特別な意味と従来の使用法を持ち、特定のリダイレクト操作によって暗示されます。それらは、それぞれ標準入力、標準出力、標準エラーと呼ばれます。通常、プログラムは標準入力から入力を取得し、標準出力に出力を書き込みます。通常、エラーメッセージは標準エラーに書き込まれます。ファイル記述子番号を指定するために、リダイレクト演算子の前に1つ以上の数字を挿入できます(介在する文字は使用できません)。
2はコンソールの標準エラーです。
1はコンソールの標準出力です。
これは標準のUnixであり、WindowsもPOSIXに従います。
E.g。実行するとき
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」で役立ちます。使用情報をstderrに出力するようなプログラムもあります。
覚えやすくするため
- 1 =標準出力(プログラムは通常の出力を出力します)
- 2 =標準エラー(プログラムがエラーを出力する)
&quot; 2&gt;&amp; 1&quot;代わりにstderrに送信されるすべてのものを、代わりにstdoutにポイントします。
エラーリダイレクトに関するこの投稿を読むこともお勧めします。件名は詳細に説明されています。
プログラマーの観点からは、まさにこれを意味します:
dup2(1, 2);
manページを参照してください。
2&gt;&amp; 1
がコピーであるということも、理由を説明しています...
command >file 2>&1
...は...とは異なります。
command 2>&1 >file
1つ目は両方のストリームを file
に送信し、2つ目はエラーを stdout
に送信し、通常の出力を file
に送信します。
人々、リダイレクトターゲットの現在の場所に関する paxdiablo のヒントを常に覚えておいてください。それは重要重要です。
2&gt;&amp; 1
演算子の個人用ニーモニックは次のとおりです:
-
&amp;
は'and'
または'add'
を意味すると考えます(文字はアンペア - および ではありませんか?) - つまり、 '
2
(stderr)を1
(stdout)が既に/現在の場所にリダイレクトし、 add の両方になるストリーム。
他の頻繁に使用されるリダイレクト 1&gt;&amp; 2
でも同じニーモニックが機能します:
-
&amp;
を考えてand
またはadd
を意味します...(アンパサンドについて知っていますか?) >
- つまり、 '
1
(stdout)を2
(stderr)がすでに/現在どこにリダイレクトし、 add 両方になるストリーム。
常に覚えておいてください:リダイレクトのチェーンは、「最後から」、右から左に読む必要があります(左から右にではありません)。
/ foo
がシステムに存在せず、 / tmp
が存在することを提供しました&#8230;
$ 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
略記
これは、エラーをstdoutまたはターミナルに渡すようなものです。
つまり、 cmd
はコマンドではありません:
$cmd 2>filename
cat filename
command not found
エラーは次のようなファイルに送信されます。
2>&1
標準エラーが端末に送信されます。
入力のリダイレクト
入力のリダイレクトにより、ファイルの名前が ファイルを読むために開かれる単語の展開の結果 記述子n、またはnが標準入力(ファイル記述子0)の場合 指定されていません。
入力をリダイレクトする一般的な形式は次のとおりです。
[n]<word
出力のリダイレクト
出力のリダイレクトにより、ファイルが nameは、書き込み用に開かれる単語の展開の結果です ファイル記述子n、またはnの場合は標準出力(ファイル記述子1) 指定されていません。ファイルが存在しない場合は作成されます。それであれば 存在しない場合は、サイズがゼロに切り捨てられます。
出力をリダイレクトする一般的な形式は次のとおりです。
[n]>word
ファイル記述子の移動
リダイレクト演算子
[n]<&digit-
ファイル記述子の数字をファイル記述子nに移動する、または nが指定されていない場合、標準入力(ファイル記述子0)。 nに複製された後、数字は閉じられます。
同様に、リダイレクト演算子
[n]>&digit-
ファイル記述子の数字をファイル記述子nに移動する、または nが指定されていない場合の標準出力(ファイル記述子1)。
参照:
man bash
/ ^ REDIRECT
と入力して、 redirection
セクションに移動します。詳細...
オンラインバージョンは次のとおりです。 3.6リダイレクト
PS:
多くの場合、 man
はLinuxを学ぶための強力なツールでした。
0は入力、1はstdout、2はstderrです。
1つのヒント:
somecmd&gt; 1.txt 2&gt;&amp; 1
は正しいが、 somecmd 2&gt;&amp; 1&gt; 1.txt
は完全に間違っている効果なし!