![Windows cmd 输出重定向到标准输入( >&0 )](https://linux22.com/image/1421180/Windows%20cmd%20%E8%BE%93%E5%87%BA%E9%87%8D%E5%AE%9A%E5%90%91%E5%88%B0%E6%A0%87%E5%87%86%E8%BE%93%E5%85%A5%EF%BC%88%20%3E%260%20%EF%BC%89.png)
从问题在 Stackoverflow 上,我一直在测试从/到 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
将等待而不会出现任何错误,但当按下某个键时会显示错误
最后一根稻草是 stderr 重定向。当使用将输出发送到 stderr 并将其重定向到 stdin 的内部命令时,例如
call "noFile" 2>&0
dir "|" 2>&0
结果是 cmd.exe 将被关闭。但并非总是如此。例如
dir "|" * 2>&0
dir * "|" 2>&0
工作无问题,隐藏发送到 stderr 的文本并打印其余信息。
所以,问题是,这是一个错误吗?它是否记录在某处而我无法找到它,或者这是预期的行为而我遗漏了一些明显的东西?
答案1
鉴于 CMD.EXE 的文档严重不足,我不确定预期的行为应该是什么。我当然没有看到任何关于预期行为的文档。所以我认为你很难找到任何人可以明确回答这些行为是否是错误。但我同意它肯定是不一致的,至少在我看来是一个设计缺陷。
我不会将这种情况描述为混乱,因为特定命令的行为似乎是可重现的。但 CMD.EXE 是不一致的,因为我看不出有任何方法可以在不进行测试的情况下预测任何一个命令的行为。
我没有任何解释,但我确实对行为有一些精细的分类。
只要没有命令实际尝试将任何内容写入重定向输出,将 stdout 或 stderr 重定向到 stdin 就可以正常工作。只有当内部命令在重定向到 stdin 后尝试写入 stdout 或 stderr 时,才会发生奇怪的行为。
我扩展了您的测试,并看到了以下不同的行为:
重定向 STDERR2>&01
我没有进行过详尽的测试,但我测试过的每个写入 stderr 的内部命令都会在 stderr 已重定向到 stdin 时立即终止命令会话。示例包括:
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
重定向 STDOUT1>&0
以下是我所见过的重定向标准输出的行为:
1)输出消失在以太中,没有任何错误消息。
例子:
vol >&0
copy /-y file1 existingFile2 >&0
move /-y file1 existingFile2 >&0
2) 输出失败,错误消息显示到 stderr。单个命令可以生成多条失败消息,每次尝试写入 stdout 失败时都会生成一条失败消息。
例子:
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) 输出失败,批处理终止。如果错误发生在被调用的子程序中,则即使在批处理终止后,活动的 SETLOCAL 仍然有效。在这方面,它的行为很像致命的语法错误。
到目前为止,我只看到一个命令表现出这种行为:
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
答案2
我第一次在 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
答案3
>& 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.
& 重定向运算符将输出或输入从一个指定句柄复制到另一个指定句柄。复制句柄时,将复制该句柄原始实例的所有特征。例如,如果句柄具有只写访问权限,则该句柄的所有副本都具有只写访问权限。您不能将具有只读访问权限的句柄复制到具有只写访问权限的句柄中。