Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Потоки Основы командной строки

В каждом языке есть собственный способ напечатать результат на экран:

javascript

console.log('hello!');

php

<?php

echo 'hello!';

python

print('hello!')

java

System.out.print("hello!");

ruby

puts 'hello!'

Несмотря на разнообразие языков и способов печати, с точки зрения операционной системы, которая запускает программу, все они работают абсолютно идентично. При старте любой программы операционная система связывает с ней три потока:

  • STDIN (Standard Input)
  • STDOUT (Standard Output)
  • STDERR (Standard Error)

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

Здесь нужно сказать, что хорошее понимание этой темы требует знания устройства операционных систем, в частности подсистемы, отвечающей за процессы и файловую систему. В двух словах, никакой язык программирования не может знать про существование экрана, а уж тем более не может с ним взаимодействовать. Ответственность за взаимодействие с железом целиком и полностью лежит на плечах операционной системы, а программы могут только лишь попросить операционную систему выполнить ту или иную задачу. При таком разделении реализация языков программирования сильно упрощается. Достаточно знать про существование STDOUT и уметь писать в него, а дальше всё сделает операционная система. Это значит, что программа, написанная на одном компьютере, без проблем запустится на другом с другой конфигурацией и монитором (или даже без монитора).

Самое удивительное начинается дальше. ОС позволяет подменять эти потоки при старте системы, что открывает интересные возможности. Например, вывод любой команды, запущенной в bash, можно записать в файл вместо вывода на экран.

ls -la > output

Запустив эту команду, вы увидите, что на экране ничего не отобразилось, но в текущей директории появился файл output.

cat output

total 44
drwxr-xr-x 5 kirill.m kirill.m 4096 Aug 29 09:39 .
drwxr-xr-x 8 root     root     4096 Apr 26 10:38 ..
-rw------- 1 kirill.m kirill.m 1822 Aug 29 08:45 .bash_history
-rw-r--r-- 1 kirill.m kirill.m  220 Aug 31  2015 .bash_logout
-rw-r--r-- 1 kirill.m kirill.m 3771 Aug 31  2015 .bashrc
drwx------ 2 kirill.m kirill.m 4096 Mar 30 18:10 .cache
-rw------- 1 kirill.m kirill.m   55 Aug 28 18:49 .lesshst
drwxrwxr-x 2 kirill.m kirill.m 4096 Aug 29 08:35 .nano
-rw-rw-r-- 1 kirill.m kirill.m    0 Aug 29 09:39 output
-rw-r--r-- 1 kirill.m kirill.m  655 May 16  2017 .profile
drwx------ 2 kirill.m kirill.m 4096 Jan 22  2018 .ssh
-rw------- 1 kirill.m kirill.m  513 Aug 29 08:06 .viminfo

Операция, которую мы сделали выше, называется перенаправление потоков. Символ > означает, что нужно взять вывод из команды, указанной слева, и отправить его в файл, указанный справа. > всегда перезаписывает файл. Такое перенаправление работает с абсолютно любой командой, которая выводит результаты своей работы в консоль.

grep alias .bash_profile > result
cat result

alias fixssh='eval $(tmux showenv -s SSH_AUTH_SOCK)'

Если нужно не перезаписывать, а добавлять, то используйте >>.

Для экспериментов с выводом удобно использовать встроенную в шелл команду echo. Она принимает на вход строчку и выдаёт её в STDOUT, который уже можно перенаправлять.

# > перетирает файл
echo 'hi' > result
cat result

hi

echo 'hello' > result
cat result

hello

# >> добавляет содержимое в конец файла
echo 'hello' >> result
cat result

hello
hello

Кроме стандартного вывода, с каждым процессом ассоциируются два дополнительных потока: один STDIN (стандартный ввод) и STDERR (вывод ошибок). STDIN работает в обратную сторону: через него программа может получать данные на вход. В *nix-системах встроена утилита wc (word count — "количество слов"). Она умеет считать количество слов, строк или символов в файле. Когда мы говорим о файле, то в *nix это почти всегда означает, что данные можно передать и в стандартный поток ввода.

# Флаг l (l, а не 1) говорит о том, что надо считать количество строк
wc -l < result

2

Выглядит довольно логично — стрелка меняет своё направление в другую сторону и содержимое файла отправляется в STDIN запускаемой программы wc. Теперь объединим перенаправление ввода и вывода:

wc -l < result > output
cat output

2

Кстати, таким же способом можно отправить вывод на печать, но оставлю эту возможность на самостоятельное изучение.

Process

Последний вопрос связан с тем, зачем нужен поток STDERR. Он, как и STDOUT, по умолчанию идёт на экран. STDERR позволяет отделить нормальный вывод программы от возникающих ошибок. Такой подход удобен при ведении логов, для реагирования и отладки. Будьте осторожны, перенаправление вывода в файл перенаправляет только STDOUT. Убедиться в этом очень просто. Если попробовать отобразить содержимое несуществующей директории, то команда ls выдаст ошибку:

ls lala

ls: cannot access 'lala': No such file or directory

Теперь попробуем перенаправить вывод в файл output

ls lala > output

ls: cannot access 'lala': No such file or directory

Перенаправление есть, но сообщение вывелось на экран. Это произошло именно по той причине, что STDERR остался привязан к экрану, а внутри файла output — пустота. Решить эту задачу можно несколькими способами. Например, перенаправив STDERR в STDOUT, либо отправив их оба в файл.

Перенаправление STDERR в STDOUT

Часто стандартный поток ошибок объединяют со стандартным потоком вывода, чтобы можно было обрабатывать ошибки и результат выполнения вместе. К примеру:

# Сначала STDOUT перенаправляется в файл, затем STDERR перенаправляется в STDOUT, продолжая запись в файл
ls lala > output 2>&1
cat output

ls: cannot access 'lala': No such file or directory

2>&1, написанное перед > output, не будет работать, так как когда интерпретатор прочитает 2>&1, он еще не знает, куда перенаправлен стандартный поток вывода, поэтому потоки ошибок и вывода не будут объединены:

ls lala 2>&1 > output

ls: cannot access 'lala': No such file or directory

В Unix за каждым потоком закреплён определённый номер, который является файловым дескриптором с потоками ввода и вывода. 2 в данном случае обозначает номер потока STDERR. Существуют следующие стандартные потоки ввода-вывода: STDIN — 0, STDOUT — 1, STDERR — 2. В командных оболочках, произошедших от C Shell, по правилам синтаксиса для указания потока, в который осуществляется перенаправление, нужно добавлять символ & после символа перенаправления.

Перенаправление STDERR бывает полезно само по себе, без вывода в файл.

#  STDERR просто перенаправляется в другой поток (STDOUT)
cd lala 2>&1

-bash: cd: lala: No such file or directory

Перенаправление конкретного потока в файл

Чтобы перенаправить конкретный поток, нужно указать его номер перед >.

#  Таким образом можно сразу перенаправить STDERR в файл
cd lala 2> output
cat output

-bash: cd: lala: No such file or directory

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

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

# Оба потока, STDERR и STDOUT, перенаправляются в файл
cd lala &> output
cat output

-bash: cd: lala: No such file or directory

Дополнительные материалы

  1. Bash Reference Manual — redirections

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Фронтенд-разработчик
Профессия
с нуля
Разработка фронтенд-компонентов для веб-приложений
8 декабря 10 месяцев
Иконка программы Python-разработчик
Профессия
с нуля
Разработка веб-приложений на Django
8 декабря 10 месяцев
Иконка программы Java-разработчик
Профессия
с нуля
Разработка приложений на языке Java
8 декабря 10 месяцев
Иконка программы PHP-разработчик
Профессия
с нуля
Разработка веб-приложений на Laravel
8 декабря 10 месяцев
Иконка программы Инженер по тестированию
Профессия
с нуля
Ручное тестирование веб-приложений
22 декабря 4 месяца
Иконка программы Node.js-разработчик
Профессия
с нуля
Разработка бэкенд-компонентов для веб-приложений
8 декабря 10 месяцев
Иконка программы Fullstack-разработчик
Профессия
с нуля
Разработка фронтенд- и бэкенд-компонентов для веб-приложений
8 декабря 16 месяцев
Иконка программы Верстальщик
Профессия
с нуля
Верстка с использованием последних стандартов CSS
в любое время 5 месяцев
Иконка программы Аналитик данных
Профессия
В разработке с нуля
Сбор, анализ и интерпретация данных
дата определяется 8 месяцев

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и соглашаетесь с «Условиями использования»