Стандартные потоки вывода (stdout) Windows
07.02.2018
Категория: Разное
С помощью переназначения устройств ввода/вывода одна программа может направить свой вывод на вход другой или перехватить вывод другой программы, используя его в качестве своих входных данных. Таким образом, имеется возможность передавать информацию от процесса к процессу при минимальных программных издержках.
Есть 3 файловых дескриптора: stdin — стандартный ввод, stdout — стандартный вывод и stderr — стандартный поток ошибок. В скриптах 1 означает stdout, а 2 — stderr.
Практически это означает, что для программ, которые используют стандартные входные и выходные устройства, операционная система позволяет:
- перенаправлять
stdoutв файл - перенаправлять
stderrв файл - перенаправлять
stdoutвstderr - перенаправлять
stderrвstdout - перенаправлять
stderrиstdoutв файл - перенаправлять
stderrиstdoutвstdout - перенаправлять
stderrиstdoutвstderr - перенаправление
stderrиstdoutпо конвейеру
Все вышесказанное является привычной обыденностью для любого пользователя любой nix системы, но в среде Windows, данные возможности применяются крайне редко, хотя на самом деле они там есть и всё практически идентично.
А теперь примеры:1. Перенаправление стандартного потока программы в файл с заменой содержимого файла
ping ya.ru -t > log.txt
ping ya.ru -t 1> log.txt
при этом на экран ничего кроме ошибок не выводится, а все записывается в лог. Если остановить пинг, и запустить заново, предыдущий лог полностью затирается новым.
2. Перенаправление стандартного потока программы в файл с до записью содержимого лога
ping ya.ru -t >> log.txt
Тоже самое, но при прерывание пинга и начале нового, старое содержимое лога не затрется, а новое дописывается в конец
ping ya.ru -t 1>> log.txt
3. Перенаправление потока ошибок программы в фаил с заменой содержимого
ping ya.ru -t 2> log.txt
при этом, стандартный поток программы пойдет на экран, а ошибки будут записаны в лог, с заменой содержимого.
4. То же самое, но с до записью содержимого лога.
ping ya.ru -t 2>> log.txt
5. Следующая конструкция позволяет перенаправить информацию между потоками (между стандартным потоком и потоком ошибок, или наоборот).
ping ya.ru > log.txt 2>&1
или с до записью лога
ping ya.ru >> log.txt 2>&1
В данном примере стандартный поток ошибок пересылается в стандартный поток (конструкция 2>&1) а потом стандартный поток (уже с завернутым в него потоком ошибок) посылается в лог.
6. В этом примере все наоборот, стандартный поток, пересылается в поток ошибок и уже поток ошибок перенаправляется в лог:
ping ya.ru > log.txt 1>&2
или с до записью лога
ping ya.ru >> log.txt 1>&2
7. По аналогии с Linux системами в Windows можно перенаправить весь или часть вывода программы в виртуальное устройство, а проще говоря слить в мусор.
Таким устройством является nul, и делать перенаправление в него можно используя все выше представленные комбинации. Например
ping ya.ru > nul
В Linux есть еще одна конструкция перенаправления, а именно &>/var/log/log.txt, она перенаправляет ВСЕ без исключения потоки программы в указанное место, по сути являясь более коротким и более грамотным аналогом конструкции >log.txt 1>&2. Но к сожалению в Windows это не работает.
А теперь давайте немного разберемся в прикладных различиях между работой данных методов. В нормальных приложениях все разбито на потоки, но у большинства виндовых утилит это не так, пинг например, пишет все в стандартный поток (на экран), поэтому для него конструкция вида 2> не имеет смысла. Но есть еще не виндовые утилиты, для примера возьмем curl (мой любимый).
Он разделяет 3 вида вывода, вывод полезной информации, вывод служебной информации и вывод ошибок. Если перенаправить вывод так: > или >> или 1> или 1>> то по завершению запроса отобразится служебная информация о запросе, а вся полезная информация уйдет в лог (это именно то, что уходит по конвейеру |).
А теперь сделаем заведомо ошибочный запрос, изменив протокол http на http3 не меняя вывода в лог. В итоге мы получим ошибку на экране.
Изменим вывод в лог на один из этих: 2> или 2>> ошибка ранее выводившаяся на экран, попала в лог, и на экране ничего не будет (служебной информации нет, так как запрос произведен не был).
Вернемся к первому скриншоту на котором мы видим вывод служебной информации, по сути, не будь у курла ключа -s который подавляет вывод служебной информации, нам пришлось бы пользоваться конструкциями из пятого и шестого примеров.
И вывод был бы таким:
То есть, полная тишина, вся информация, как то полезный вывод, ошибки программы, служебная информация, все ушло в лог.
На данном скриншоте, конструкцией 2>&1 мы завернули поток ошибок в стандартный поток, а конструкцией > 5555.txt стандартный поток перенаправили в лог. Если вместо > 5555.txt использовать 2> 5555.txt, то есть перенаправить в лог стандартный поток ошибок, мы увидим весь вывод программы (и ошибки, и служебную информацию и полезный вывод) на экране. Конструкция 2>&1 имеет больший приоритет, а по ней уже все завернуто в стандартный поток.
Делать пример с заворотом стандартного потока в поток ошибок (1>&2) я не буду, ибо там все точно так же.
Надеюсь логика понятна…
Так же с помощью символа< можно прочитать входные данные для заданной команды не с клавиатуры, а из определенного (заранее подготовленного) файла. Для примера возьмем реальный и вполне полезный случай. Например, у нас есть файл log.txt и нам надо посчитать сколько в нем строк. Сделать это можно с помощью такой конструкции
find /c /v "" log.txt
но вывод будет не совсем приемлемым.
А вот если сделать так:
find /c /v "" < log.txt
то все будет именно так как надо.
Это происходит потому что в первом случае, файл обрабатывается как файл, а во втором, как поток (аналог линуксового конвейера cat log.txt |) в общем, < это виндовый аналог cat со всеми вытекающими.