Когда вы запускаете программу в командной строке, она автоматически получает два отдельных канала для вывода. Один из них - Стандартный канал вывода, Standard Output, а второй - Сдандартный канал ошибок, Standard Error.

По умолчанию они оба выводятся на экран (в оболочке, терминале или окне командной строки) и, таким образом, они смешиваются, но пользователь программы может разделить их, и перенаправить один из них или оба в файл.

Идея в том, что обычный вывод приложения идет в канал вывода, а все предупреждения и сообщения об ошибках идут в канал ошибок.

Как программист, вы решаете, какой вывод считается частью нормального хода выполнения вашей программы, и отправляете его в стандартный канал вывода. Остальное, то, что является ненормальным, попадет в стандартный канал ошибок.

Если пользователь хочет видеть только нормальный вывод, он может перенаправить канал ошибок в файл, чтобы просмотреть его позже, отдельно.

Как выводить сообщения об ошибках?

В Perl, когда программа запускается, эти два канала вывода представляются двумя символами: STDOUT для стандартного канала вывода, и STDERR для стандартного канала ошибок.

Изнутри программы Perl вы можете выводить сообщение в любой из этих каналов, поместив соответствующий символ сразу после ключевого слова print:

print STDOUT "Welcome to our little program\n";
print STDERR "Could not open file\n";

(Обратите внимание, после слов STDOUT и STDERR в этих выражениях нет запятой ,!)

Если запустить этот скрипт (perl program.pl), на экране мы увидим следующее:

Welcome to our little program
Could not open file

То есть мы не увидим, что эти сообщения пришли из разных каналов вывода.

Канал вывода по умолчанию

По сути, слово STDOUT можно опустить, и написать просто:

print "Welcome to our little program\n";
print STDERR "Could not open file\n";

Когда скрипт perl запускается, STDOUT назначается каналом вывода по умолчанию. Это значит, что любая операция вывода, для которой явно не указан канал, выведет данные в STDOUT.

Перенаправление стандартного канала вывода

(В дальнейших примерах предполагается, что вы используете bash-совместимую оболочку. Другие оболочки могут работать по-другому.)

Как пользователь, не глядя в код, мы можем разделить два канала: если выполнить команду perl program.pl > out.txt, символ > перенаправит канал вывода в файл out.txt. Так что на экране мы увидим только содержимое стандартного канала ошибок.

Could not open file

Если открыть файл out.txt (с помощью Блокнота, vim или любого другого текстового редактора), мы увидим в нем текст Welcome to our little program.

Перенаправление стандартного канала ошибок

С другой стороны, если запустить скрипт командой perl program.pl 2> err.txt, то символ 2> перенаправит канал ошибок в файл err.txt.

На экране мы увидим:

Welcome to our little program

А если откроем файл err.txt, то в нем обнаружим: Could not open file.

Перенаправление обоих каналов

Мы можем перенаправить и оба канала одновременно с помощью обоих символов командной строки.

Запустив скрипт командой perl program.pl > out.txt 2> err.txt, на экране мы ничего не увидим. Все, что выводилось в стандартный канал вывода, окажется в файле out.txt, а все, что было в канале ошибок - в err.txt.

В этих примерах названия файлов out.txt и err.txt совершенно произвольны. Вы можете использовать любые пути по своему усмотрению.

/dev/null

В системах Unix/Linux существует специальный файл под названием /dev/null. Он работает как черная дыра. Все, что записывается в этот файл, исчезает без следа. В основном это используется, когда пользователь хочет выкинуть либо стандартный вывод, либо ошибки запускаемого приложения.

Например, у нас есть приложение, которое мы не можем изменить, и оно вываливает кучу сообщений в стандартный канал ошибок. Если мы не хотим видеть это на экране, можем перенаправить их в файл. Но если так сделать, диск может быстро переполниться. Так что мы перенаправляем канал ошибок в /dev/null, и операционная система помогает нам избавиться от «мусора».

perl program.pl 2> /dev/null

nul в MS Windows

В MS Windows /dev/null соответствует просто nul

perl program.pl > nul перенаправит стандартный вывод в никуда, а perl program.pl 2> nul сделает то же со стандартным каналом ошибок.

Поддержка Unix/Linux/Windows?

Раздельный вывод в STDOUT и STDERR внутри Perl'а работает на любой операционной системе, но перенаправление может не сработать. Это зависит от того, как работает операционная система, или, точнее, оболочка (командная строка).

Большая часть примеров выше должна работать на Unix/Linux, как и на MS Windows. Конкретно /dev/null работает только на системах Unix/Linux.

Порядок вывода (буферизация)

Небольшое предупреждение:

Этот код:

print "до";
print STDERR "Небольшая проблема.\n";
print "после";

Может вывести что-нибудь вроде:

Небольшая проблема.
допосле

Обратите внимание, что «до» и «после» попали на экран после сообщения об ошибке. Несмотря на то, что мы ожидали увидеть «до», собственно, до сообщения об ошибке.

Причина этого в том, что по умолчанию Perl буферизирует вывод в STDOUT, но не буферизирует STDERR. Чтобы выключить буферизацию, можно использовать волшебную палочку $|:

$| = 1;

print "до";
print STDERR "Небольшая проблема.\n";
print "после";

доНебольшая проблема.
после

Также обычно можно решить эту проблему, добавив перевод строки в STDOUT:

print "до\n";
print STDERR "Небольшая проблема.\n";
print "после";

И вывод выглядит даже лучше:

до
Небольшая проблема.
после