Здесь есть несколько слабо связанных проблем.
Комментарий стиля: я рекомендую использовать 2>&1
без пробелов.Я даже не знал, что размеченная версия работает (я подозреваю, что она не работала в оболочке Bourne в середине 80-х), и сжатая версия - это ортодоксальный способ ее записи.
Файл-дескриптор ввода / вывода нотации не все доступны в оболочке C и производных;они доступны в оболочке Bourne и ее производных (оболочка Korn, оболочка POSIX, Bash, ...).
Разница между >file
или 2>file
и 2>&1
заключается в том, что должна делать оболочка,Первые два упорядочивают вывод, записанный в дескриптор файла (1 в первом случае, иначе стандартный вывод; 2 во втором случае, стандартная ошибка), чтобы перейти к названному файлу.Это означает, что все, что записано программой в стандартный вывод, вместо этого отправляется в файл.Третья запись обеспечивает 2 (стандартная ошибка) для перехода к тому же дескриптору файла, что и 1 (стандартный вывод);все, что записано в стандартную ошибку, отправляется в тот же файл, что и стандартный вывод.Это тривиально реализовано с использованием dup2()
.Однако стандартный поток ошибок в программе будет иметь свой собственный буфер, а стандартный поток вывода в программе будет иметь свой собственный буфер, поэтому чередование выходных данных не является полностью определенным, если выходные данные передаются в файл.
Вы запускаете команду двумя разными способами и (что неудивительно) получают два разных результата.
./a.out > outfile 2>&1
Перенаправления ввода / вывода обрабатываются слева направо,Первый отправляет стандартный вывод на outfile
.Вторая отправляет стандартную ошибку в то же место, что и стандартный вывод, поэтому она также переходит к outfile
.
./a.out 2>&1 >outfile
Первое перенаправление отправляет стандартную ошибку вместо, где идет стандартный вывод, который в настоящее время является терминалом.Затем второе перенаправление отправляет стандартный вывод в файл (но оставляет стандартную ошибку при отправке на терминал).
Программа использует функцию printf()
и системный вызов write()
.Когда используется функция printf()
, она буферизует свой вывод.Если выходные данные отправляются на терминал, то это обычно «буферизованная строка», поэтому выходные данные появляются, когда в буфер добавляется новая строка.Однако, когда вывод идет в файл, он «полностью буферизуется» и вывод не появляется, пока поток файла не будет очищен или закрыт или буфер не заполнится.Обратите внимание, что stderr
не полностью буферизован, поэтому записанные в него выходные данные появляются немедленно.
Если вы запустите свою программу без перенаправления ввода-вывода, вы увидите:
standard output.
standard err, output
Byнапротив, системный вызов write()
немедленно передает данные в дескриптор выходного файла.В примере вы пишете со стандартной ошибкой, и то, что вы пишете, появится сразу.То же самое произошло бы, если бы вы использовали fprintf(stderr, ...)
.Однако предположим, что вы изменили программу для записи в STDOUT_FILENO;затем, когда выходные данные находятся в файле, выходные данные будут отображаться в следующем порядке:
standard err, output
standard output.
, поскольку write()
небуферизован, а printf()
буферизован.