web-dev-qa-db-ja.com

標準入力へのWindowscmd出力リダイレクト(>&0)

Stackoverflowの question から、stdinストリームとの間のリダイレクトでテストしています。そして、このテストは、データをstdinストリームに送信しようとして、何が起こるかを確認するために、明らかに混沌とした動作で終了します。

次のようなコマンド

echo testing >&0
dir >&0 
cls >&0

System can not write to the specified deviceを生成します(おそらくstdinは読み取り専用ストリームのようです)が、

  • vol >&0はエラーを表示しません

  • set /p "var=Prompt" >&0は、プロンプトを表示せず、エラーも表示せずに入力を待機します

  • pause >&0はエラーなしで待機しますが、キーを押すとエラーが表示されます

そして最後のストローはst​​derrリダイレクトです。 stdinにリダイレクトされた状態で出力をstderrに送信する内部コマンドを使用する場合。

call "noFile" 2>&0
dir  "|" 2>&0

その結果、cmd.exeが閉じられます。しかしいつもではない。のようなもの

dir "|" * 2>&0
dir * "|" 2>&0

stderrに送信されたテキストを非表示にし、残りの情報を印刷して、問題なく動作します。

だから、問題は、これはバグですか、それはどこかに文書化されていて私はそれを見つけることができませんか、それともこれは予想される動作であり、私が欠けていることは明らかです?

4
MC ND

CMD.EXEがひどく文書化されていないことを考えると、期待される動作がどうあるべきかわかりません。私は確かに、予想される動作が何であるかについてのドキュメントを見たことがありません。ですから、行動のいずれかがバグであるかどうかについて決定的な答えを与えることができる人を見つけるのは難しいと思います。しかし、私はそれが確かに一貫性がなく、少なくとも私には設計上の欠陥のように思われることに同意します。

特定のコマンドの動作が再現可能であるように見えるという点で、状況を混沌としたものとして特徴付けることはしません。しかし、CMD.EXEは、テストせずに1つのコマンドがどのように動作するかを予測する方法がわからないという点で一貫性がありません。

説明はありませんが、行動の分類は洗練されています。

Stdoutまたはstderrのstdinへのリダイレクトは、リダイレクトされた出力に実際に何かを書き込もうとするコマンドがない限り、完全に正常に機能します。奇妙な動作は、内部コマンドがstdinにリダイレクトされた後にstdoutまたはstderrに書き込もうとした場合にのみ発生します。

テストを拡張したところ、次のような明確な動作が見られました。

リダイレクトされたSTDERR 2>&01

徹底的なテストは行っていませんが、stderrがstdinにリダイレクトされている場合、stderrに書き込むすべての内部コマンドは、コマンドセッションをすぐに終了します。例は次のとおりです。

cd invalidPath 2>&0
vol x 2>&0
copy nonExistentFile 2>&0
move nonExistentFile 2>&0
set nonExistentVariable 2>&0
dir nonExistentFile 2>&0

あなたが例外だと思ったことは、実際には決してstderrに書き込みません。リダイレクトせずに以下を試してください。エラーメッセージが表示されないことがわかります。

dir nonExistentFIle *

したがって、stderrがstdinにリダイレクトされた場合、コマンドがコマンドセッションを終了する理由はありません。

DIRは、提供されたすべてのファイルマスクで一致するファイルが見つからない場合にのみ、エラーメッセージを出力します。

:: This prints an error message
dir nonExistentFile1 nonExistentFile2

:: So this terminates the command session
dir nonExistentFile1 nonExistentFile2 2>&0


リダイレクトされたSTDOUT 1>&0

リダイレクトされたstdoutで見た動作は次のとおりです。

1)出力はエラーメッセージなしでエーテルに消えます。

例:

vol >&0
copy /-y file1 existingFile2 >&0
move /-y file1 existingFile2 >&0


2)出力が失敗し、エラーメッセージがstderrに表示されます。 1つのコマンドで、stdoutへの書き込みに失敗するたびに1つずつ、複数の失敗メッセージを生成できます。

例:

cd >&0
echo Hello >&0

:: This generates 2 error messages, one for the time,
:: and another for the subsequent empty line
time /t >&0


3)出力に失敗し、バッチ処理を終了します。 CALLedサブルーチン内でエラーが発生した場合、バッチ終了後もアクティブなSETLOCALは有効なままです。この点で、致命的な構文エラーのように動作します。

これまでのところ、この動作を示すコマンドは1つだけです。

dir >&0

DIRコマンドは、出力の試行ごとにエラーメッセージを生成することを期待します。しかし、最初の行で失敗した後に終了したようで、バッチ処理も中止されます。


4)一部のコマンドは複数の動作を示します。

例:

:: This SET command generates an error message for each
:: defined variable (behavior 2)
set >&0

:: But this SET command fails to display the Prompt without
:: error message (behavior 1). Note that the echo of user input
:: is written directly to :con. It does not use stdout or stderr.
set "var=Prompt" >&0

:: A single PAUSE exhibits both behaviors 1 and 2. The Prompt to
:: press a key simply dissapears, and the echo of the user input
:: generates an error. Note that in this case, the echo of user
:: input is written to stdout.
pause >&0
4
dbenham

見てください https://www.Microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/redirection.mspx?mfr=true (アーカイブ済み)

>& Writes the output from one handle to the input of another handle.
<& Reads the input from one handle and writes it to the output of another handle.

&リダイレクト演算子は、ある指定されたハンドルから別の指定されたハンドルに出力または入力を複製します。ハンドルを複製すると、ハンドルの元の出現のすべての特性が複製されます。たとえば、ハンドルに書き込み専用アクセス権がある場合、そのハンドルのすべての複製には書き込み専用アクセス権があります。読み取り専用アクセスのハンドルを書き込み専用アクセスのハンドルに複製することはできません。

0
joanmib

私は2010年にこのバグを最初に誤って発見しました。最終的には私の間違いを発見しました。stderrをストリーム0(現在のプロセスのstdin)にリダイレクトすることは論理的に意味がなく、cmd.exeにはそのシナリオのハンドラーがなかったため、問題は解決しました。でる。正しい構文は次のとおりです。

dir 2> nul(エラーをリダイレクトしたいだけの場合)

または

dir 2> nul 1>&2(成功した出力もリダイレクトしたい場合)。

基本的に、組み込みコマンドのCMD.EXEでは未処理の例外です。これが数年前の私の記事です: http://dnlongen.blogspot.com/2013/05/how-to-crash-windows-Shell.html

0