Учитывая, что файл 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