Bashのマニュアルのリダイレクトセクションにあるタイプミスですか?

Bashのマニュアルのリダイレクトセクションにあるタイプミスですか?
Note that the order of redirections is significant.  For example, the command

          ls > dirlist 2>&1

   directs both standard output and standard error to the file dirlist, 
   while the command

          ls 2>&1 > dirlist

   directs  only  the  standard  output  to  file  dirlist,  because the 
   standard error was duplicated from the standard output before the standard
   output was redirected to dirlist.

今、最後の部分が私を混乱させます。この場合、標準エラーが端末に出力され、STDOUT がディレクトリリストファイルに移動されます。そのようなことが起こりますが、マニュアルを理解するわけではありません。

「標準出力がディレクトリリストにリダイレクトされた後、標準エラーが標準出力からコピーされるためです」と言う必要があるようです。 STDOUTがファイルに渡される前にSTDERRがSTDOUTに転送された場合、ファイルにSTDOUTとSTDERRは含まれませんか?

誰でもこの問題を解決するのに役立ちますか?私の読解力が足りないせいか?この文脈では、「繰り返し」という言葉を使うのは私にとっては少し奇妙に見えます。たぶんこれは私を混乱させるかもしれません。

答え1

コピーここで本当に重要な部分です。

リダイレクトされる前に、ファイル記述子がどこに行くかを見てみましょう。これは通常現在の端末です。たとえば、次のようになります。

STDOUT ---> /dev/pts/1
STDERR ---> /dev/pts/1

リダイレクトなしで呼び出すと、ls -l出力とエラーメッセージが私の端末に移動します/dev/pts/1

STDOUTまずファイル()にリダイレクトすると、ls -l > dirlist次のようになります。

STDOUT ---> /home/bon/dirlist
STDERR ---> /dev/pts/1

いつ私たちがそれからSTDERRリダイレクトコピーSTDOUTls -l > dirlist 2>&1)のファイル記述子は、STDERR次のコピーに移動します/home/bon/dirlist

STDOUT ---> /home/bon/dirlist
STDERR ---> /home/bon/dirlist

私たちが望むなら最初リダイレクトするファイル記述子()のコピーSTDERRSTDOUTls -l 2>&1

STDOUT ---> /dev/pts/1
STDERR ---> /dev/pts/1

そしてそれから STDOUTファイル(ls -l 2>&1 > dirlist)について以下を取得します。

STDOUT ---> /home/bon/dirlist
STDERR ---> /dev/pts/1

この時点でSTDERR私たちはまだターミナルに行かなければなりません。

ご覧のとおり、マニュアルページの順序は正しいです。


テストリダイレクト

今すぐテストしてみましょう。を使用すると、現在のプロセスがどこに行くか(fd 1を使用)と(fd 2を使用)をls -l /proc/$$/fd/確認できます。STDOUTSTDERR

$ ls -l /proc/$$/fd/
total 0
lrwx------ 1 bon bon 64 Jul 24 18:19 0 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 18:19 1 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 07:41 2 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 18:19 255 -> /dev/pts/1

ファイル記述子が指す場所を表示する小さなシェルスクリプトを作成しましょう。これにより、lsコールシェルのリダイレクトを含む、常にコール時にステータスを取得できます。

$ cat > lookfd.sh
#!/bin/sh
ls -l /proc/$$/fd/
^D
$ chmod +x lookfd.sh

(を使用すると、CtrlDファイル終了文字を送信してからcat読み取りコマンドを停止できますSTDIN。)

次に、さまざまなリダイレクトの組み合わせを使用してこのスクリプトを呼び出します。

$ ./lookfd.sh 
total 0
lrwx------ 1 bon bon 64 Jul 24 19:08 0 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 19:08 1 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 19:08 2 -> /dev/pts/1
lr-x------ 1 bon bon 64 Jul 24 19:08 255 -> /home/bon/lookfd.sh
$ ./lookfd.sh > foo.out
$ cat foo.out 
total 0
lrwx------ 1 bon bon 64 Jul 24 19:10 0 -> /dev/pts/1
l-wx------ 1 bon bon 64 Jul 24 19:10 1 -> /home/bon/foo.out
lrwx------ 1 bon bon 64 Jul 24 19:10 2 -> /dev/pts/1
lr-x------ 1 bon bon 64 Jul 24 19:10 255 -> /home/bon/lookfd.sh
$ ./lookfd.sh 2>&1 > foo.out
$ cat foo.out 
total 0
lrwx------ 1 bon bon 64 Jul 24 19:10 0 -> /dev/pts/1
l-wx------ 1 bon bon 64 Jul 24 19:10 1 -> /home/bon/foo.out
lrwx------ 1 bon bon 64 Jul 24 19:10 2 -> /dev/pts/1
lr-x------ 1 bon bon 64 Jul 24 19:10 255 -> /home/bon/lookfd.sh
$ ./lookfd.sh > foo.out 2>&1
$ cat foo.out 
total 0
lrwx------ 1 bon bon 64 Jul 24 19:11 0 -> /dev/pts/1
l-wx------ 1 bon bon 64 Jul 24 19:11 1 -> /home/bon/foo.out
l-wx------ 1 bon bon 64 Jul 24 19:11 2 -> /home/bon/foo.out
lr-x------ 1 bon bon 64 Jul 24 19:11 255 -> /home/bon/lookfd.sh

STDOUTファイル記述子1(の場合)と2(の場合)が異なることを確認できますSTDERR。楽しみにリダイレクトしSTDINて結果を見ることもできます。

$ ./lookfd.sh < /dev/zero
total 0
lr-x------ 1 bon bon 64 Jul 24 19:18 0 -> /dev/zero
lrwx------ 1 bon bon 64 Jul 24 19:18 1 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 19:18 2 -> /dev/pts/1
lr-x------ 1 bon bon 64 Jul 24 19:18 255 -> /home/bon/lookfd.sh

(読者に残った質問:ファイル記述子255はどこを指していますか?;-))

答え2

いいえ、指示は正しいです。

最初に1がターミナルを指し、2度ターミナルを指す場合:

command  2>&1   1>somewhere

リダイレクト評価は左から右に行われます。

したがって、最初に評価2>&1してから、1fdが指す内容(ファイル記述子、通常は/ dev / ttyなど)をthe terminalfdにコピーします2

したがって、この時点でfdは、fdがかつて()を指していた2位置を指します。1the terminal

その後、そのセクションを評価して1>somewherefdのファイル記述子をコピーします(したがって、この時点でfdは現在指され、fdはまだポイントされます)。somewhere11somewhere2the terminal

したがって、1が変更される前に1から2がコピーされたので、1を「どこかに」印刷し、2を端末に印刷する。

別の順序:

command  1>somewhere 2>&1

まずfd1をにリダイレクトsomewhereしてから、同じ参照をfd 2にコピーするので、最終的に2度を指しますsomewhere。しかし、今から彼らはもはや「連絡」しません。それぞれはまだ個別にリダイレクトできます。

前任者:

command  1>somewhere 2>&1
exec 2>/dev/null

最後に fd は1を指し、somewherefd は2次に向かいます。/dev/null

fdの一般名1はSTDOUT(標準出力)、fdの一般名2はSTDERR(標準エラー、通常はSTDOUTを妨げずにエラーを表示するために使用されるため)です。

答え3

ここで混乱している部分は、stderrをstdoutにリダイレクトすると、実際に2つのストリームをリンクするという誤解だと思います。

これは完全に合理的な考えですが、2>&1stderrに書くときに起こるのは、stdoutが何を書いているのかを見て、同じ場所自体に書き込むことです。したがって、後でstdoutに他の場所に書き込むように指示すると、移動されたstderrのターゲットには影響しません。

私はこれが少し直観にずれていると思いますが、これがうまくいく方法です。投稿したい場所を設定し、すべての人に「私をコピーしてください」と言ってください。その内容が明確になることを願っています...

答え4

コピー...

重要だがもっと重要なこと多くの混乱の源。本当に簡単です。この答えは単に「根本的な」例です。

許容される回答は良いですが、長すぎて「繰り返し」を強調しています。

質問は賢明に次のように終わります。

これ繰り返しという単語の使用このような場合は、ちょっと変だと思います。たぶんこれは私を混乱させるかもしれません。

私はbash表記を使用し、ファイルが「1」と「2」を処理するように「one」と「two」変数を定義しました。 (出力)リダイレクト演算子>は割り当てです=&そして$「価値」を意味します。

man bash はい(デフォルトは「1」を追加)

ls 1>dirlist 2>&1      # both to dirlist
ls 2>&1 1>dirlist      # 1 to dirlist, 2 stays on tty/screen 

次のようになります。

one=dirlist  two=$one

そして

two=$one   one=dirlist

私や他の人にとって、これは自動的に行われるわけではありません。最初の行は出て、両方$oneとも$two「dirlist」を含みます。確かに。

2行目は無駄な割り当てで始まります。どちらの定義も「TTY」で始まります(やや象徴的に)。方向;この割り当ては値を変更せず、変数(ファイルハンドルなど)の場合、魔法のようにリンクされていません。変数はtwo次の影響を受けませんone=dirlist。当然じゃない。

誰か(6年前)「コピー」または「複製」を「指す」に変えようと提案した後、悟りました。それも混乱するでしょう。

そのような複製やポインタの意味論は必要ありません。おそらくもっと注意が必要なのはアンパサンドです。演算子/トークン/何でもの「値」です。

素晴らしい仕事数を得る方法を探している場合のみ快適、「完了」メッセージとボーナスとして「2」というファイルが表示されたら、次のことができます。

ls 1>2& 2>/dev/null

「と自然に読まれる。copy"/"duplicate" 1を2に設定し、両方ともnullに設定します。。しかし、アイデアが間違っていて構文が間違っています。 (ただし、構文エラーはなく、有効)

正しい計画方法は、どちらか一方をnullにリダイレクトし、もう一方を同じ場所にリダイレクトすることです。

ls 1>/dev/null 2>&1
# or 
ls 2>/dev/null 1>&2

(前の「1」は省略可能)

(わかりました。acc.Aは長すぎませんが、リストが多すぎます。可視化はとても良いですが、説明はあまり良くありません。)

関連情報