4

Из вопроса о 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, и распечатывая остальную информацию.

Итак, вопрос в том, является ли это ошибкой, она где-то задокументирована, и я не могу ее найти, или это ожидаемое поведение, и есть что-то очевидное, чего мне не хватает?

3 ответа3

4

Учитывая, что файл CMD.EXE крайне недокументирован, я не уверен, каким должно быть ожидаемое поведение. Я конечно не видел никакой документации относительно того, каково ожидаемое поведение. Поэтому я думаю, что вам будет сложно найти кого-то, кто мог бы дать однозначный ответ относительно того, является ли какое-либо из поведений ошибкой. Но я согласен, что это, безусловно, противоречиво, и мне кажется, по крайней мере, недостаток дизайна.

Я бы не охарактеризовал ситуацию как хаотичную в том смысле, что поведение конкретной команды кажется воспроизводимым. Но CMD.EXE несовместим в том, что я не вижу способа предсказать, как ведет себя одна команда без тестирования.

У меня нет никаких объяснений, но у меня есть некоторые уточненные классификации поведения.

Перенаправление stdout или stderr на stdin работает отлично, если на самом деле ни одна команда не пытается что-либо записать в перенаправленный вывод. Странное поведение возникает только тогда, когда внутренняя команда пытается записать в stdout или stderr после того, как она была перенаправлена в stdin.

Я расширил ваши тесты и увидел следующие отличительные варианты поведения:

Перенаправленный STDERR 2>&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 перенаправлен на стандартный ввод данных.

DIR выводит сообщение об ошибке только в том случае, если не удается найти какой-либо соответствующий файл во всех предоставленных масках файлов.

:: This prints an error message
dir nonExistentFile1 nonExistentFile2

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


Перенаправленный STDOUT 1>&0

Вот поведение, которое я видел для перенаправленного стандартного вывода:

1) Вывод исчезает в эфир, без каких-либо сообщений об ошибках.

Примеры:

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


2) Сбой вывода и сообщение об ошибке отображается в stderr. Одна команда может генерировать несколько сообщений об ошибках, по одному на каждую неудачную попытку записи в стандартный вывод.

Примеры:

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 остаются в силе, даже после пакетного завершения, если ошибка происходит в подпрограмме CALLed. В этом отношении он ведет себя как фатальная синтаксическая ошибка.

До сих пор я видел только одну команду, демонстрирующую такое поведение:

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
0

Посмотрите на 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.

Оператор & redirection дублирует вывод или ввод из одного указанного дескриптора в другой указанный дескриптор. Когда вы дублируете дескриптор, вы дублируете все характеристики исходного вхождения дескриптора. Например, если дескриптор имеет доступ только для записи, все дубликаты этого дескриптора имеют доступ только для записи. Вы не можете дублировать дескриптор с доступом только для чтения в дескриптор с доступом только для записи.

0

Я впервые обнаружил эту ошибку по ошибке в 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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .