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

Перенаправление потоков ввода-вывода #

Андрей Михайлович Васильев, 2022

Версии презентации


Структура потоков ввода-вывода приложения #

В момент запуска процесса ему выделяются стандартные потоки для ввода и вывода информации

  • 0, stdin — стандартный поток ввода
  • 1, stdout — стандартный поток вывода
  • 2, stderr — стандартный поток вывода сообщений об ошибках

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

Процесс во время своей работы может самостоятельно изменить направление потоков, однако эта возможность используется в основном управляющими процессами (например Bash)

flowchart LR in([0, stdin]) out([1, stdout]) stderr([2, stderr]) proc[Процесс] in --> proc proc --> out proc --> stderr

Использование stderr #

Ruby #

puts "Текст выведен на стандартный поток вывода"
STDERR.puts "Текст выведен на поток ошибок"

Python #

import sys
print("Текст на стандартный поток вывода")
print("Текст на поток ошибок", file=sys.stderr)

C++ #

#include <iostream>
int main() {
  std::cout << "Поток вывода\n";
  std::cerr << "Поток ошибок\n";
}

Потоки ввода-вывода в эмуляторе терминала #

Эмулятор терминала общается с пользователем только по двум каналам:

  • Ввод данных с помощью клавиатуры (буфера обмена)
  • Вывод текстовых (и псевдографических) данных на экран терминала

Если специальных действий не было предпринято, тогда

  • Поток событий с клавиатуры передаётся на стандартный поток ввода
  • Содержимое потоков stdout и stderr выводится на экран в истории

С точки зрения пользователя потоки stdout и stderr выводятся общим текстовым потоком

Если данные с потоков приходят одновременно, то возможно их пересечение


Использование потоками приложением ls #

Приложение ls не использует стандартный поток ввода, данные ему передаются исключительно через аргументы

  • stdout используется для вывода списка файлов
  • stderr используется для вывода информации об ошибках

Пример вывода на стандартный поток вывода:

$ ls -1 /tmp
mc-andrey
mozilla_andrey0
...

Пример вывода на поток ошибок:

$ ls /abc
ls: невозможно получить доступ к '/abc': Нет такого файла или каталога

Без применения специальных действий различить два вывода мы не сможем


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

Bash позволяет перенаправить поток вывода любой команды в файла

КОМАНДА > output_log.txt

Результат работы команды будет записан в файл output_log.txt

Перенаправление вывода приложения ls #

$ ls -l /usr/bin > /tmp/ls-output.txt
$

В результате запуска пользователю не будет выведено никакой информации, а она будет записана в файл /tmp/ls-output.txt


Перенаправление вывода команды echo #

Поток вывода можно перенаправлять и для встроенных команд Bash

echo 'Hello, world!' > text.txt

В результате будет создан файл text.txt с содержимым 'Hello, world!'


Особенности перенаправления #

С технической точки зрения перенаправление потока выглядит следующим образом:

  1. Bash получает команду на перенаправление потока с символом >
  2. Bash открывает указанный файл на запись с флагом w, запись с начала
    • Bash должен иметь возможность открыть файл
    • Всё предыдущее содержимое файла будет удалено
  3. Открытый файловый дескриптор устанавливается значением для дескриптора 1, стандартного потока вывода
  4. Происходит запуск нового процесса в изменённом окружении

Создание пустых файлов #

Помимо touch можно воспользоваться перенаправлением вывода для создания пустых файлов

> empty.txt

Пустая команда не выводит ничего, в результате будет создан файл empty.txt


Добавление в конец файла #

Помимо перезаписи файла Bash может добавлять результаты в конец текстового файла

Синтаксис:

КОМАНДА >> output_log.txt

Стандартный поток вывода будет перенаправлен в файл output_log.txt. Если файла не существовало, тогда он будет создан

Пример с использованием ls #

$ ls -l /usr/bin > ls-output.txt
$ ls -l /usr/bin >> ls-output.txt

В результате выполнения этой последовательности в файле ls-output.txt будет находиться два вывода результата запуска команды ls -l /usr/bin


Перенаправление потока stderr #

Просмотр потока stderr #

$ ls -l /some > ls-info.txt
ls: невозможно получить доступ к '/some': Нет такого файла или каталога

Хотя stdout был перенаправлен, но приложение всё-равно вывело информацию пользователю

Перенаправление потока #

Синтаксис:

КОМАНДА 2> error-info.txt

В результате будет создан файл error-info.txt, содержащий информацию из потока stderr запущенной команды

Все данные из потока stdout будут показаны пользователю


Перенаправление двух потоков в один файл #

Для решения этой задачи надо сначала перенаправить stdout в один файл, а затем перенаправить поток stderr в поток stdout:

КОМАНДА > output.txt 2>&1

Форма записи 2>&1 говорит, что поток №2 надо связать с потоком №1

Порядок указаний на перенаправления важен #

2>&1 > output.txt

Такая запись свяжет сначала поток ошибок со стандартным потоком вывода, а после уже перенаправит поток вывода в файл output.txt. В результате будет перенаправлен только стандартный поток вывода


Новая форма перенаправления потоков #

Если надо перенаправить все потоки в один файл, то можно воспользоваться &>:

КОМАНДА &> output.txt

Добавление в конец файла #

КОМАНДА &>> output.txt

В результате запуска весь вывод будет добавлен в конец файла output.txt

Избавляемся от ошибок #

Бывает так, что приложение посылает много информации на поток stderr и мы хотим его игнорировать. Для этих целей можно воспользоваться специальным файлом /dev/null:

КОМАНДА 2> /dev/null

Все данные, которые записываются в файл /dev/null, пропадают. Это могут использовать любые приложения


Приложение cat #

$ cat --help
Использование: cat [КЛЮЧ]… [ФАЙЛ]…
Печатает слияние ФАЙЛ(ов) на стандартный вывод.

Приложение считывает файлы, пути к которым переданы через аргументы, и выводит результат на стандартный поток вывода

Самое простое применение — чтение текстовых файлов

Приложение-повторятель #

Если не cat не указать файлы, то оно берёт информацию со стандартного потока ввода

Простейший текстовый редактор #

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

cat > data.txt

Для завершения работы приложения надо послать сигнал завершения потока Ctrl+D


Перенаправление потока ввода #

Для перенаправления потока ввода у процесса надо использовать следующий синтаксис:

КОМАНДА < input.txt

В результате поток ввода будет команды будет получать данные из файла input.txt

Вместе с cat его можно использовать для чтения файла:

$ cat < input.txt
...

Перенаправление для тестирования программ #

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

  1. Записать последовательность ввода от пользователя в текстовый файл
  2. Запустить приложение и перенаправить поток ввода из данного файла

В этом случае вам не придётся повторять ввод данных множество раз


Использование механизма pipe #

Помимо соединения потоков ввода и вывода с файлами Bash (операционная система) позволяет соединять поток вывода одного процесса с потоком ввода другого процесса

Данный механизм называется pipe, конвеер

В Bash для связи потоков двух процессов используется оператор |:

КОМАНДА-1 | КОМАНДА-2

В результате будут запущены КОМАНДА-1 и КОМАНДА-2, причём стандартный вывод КОМАНДА-1 будет подключён ко входу в конвеер, а выход конвеера подключён к стандартному входу программы КОМАНДА-2


Проблема длинного вывода команд #

Результат выполнения команды может не поместиться на экран, вследствие чего пользователю приходится просматривать предыдущий вывод

  • Прокручивать экран наверх с помощью мыши
  • Использовать горячие клавиши (зависит от эмулятора терминала)
    • Ctrl + Page Up, Ctrl + Page Down
    • Shift + Page Up, Shift + Page Down

Использование пейджера #

Приложение less позволяет просматривать не только текстовые файлы, но также и длинный ввод со стандартного потока

Чтобы найти нужную информацию в потоке данных их можно передать less

ls -l /usr/bin | less

Приложения-фильтры #

Для удобной обработки текстовой информации, приходящей от приложений в UNIX можно использовать приложения, нацеленные на обработку потока строк, приходящих на стандартный поток ввода

Благодаря конвеерам эти приложения зачастую объединяются

КОМАНДА | ФИЛЬТР-1 | ФИЛЬТР-2 | ФИЛЬТР-3

Приложение sort #

Приложение сортирует входящий поток строк

Рассмотрим текстовый файл data.txt:

euo
aoeu
zeou

Сортировка файла:

$ cat data.txt | sort
aoeu
euo
zeou

Приложение uniq #

Выбрасывает из входящего потока данных повторяющиеся строки. Зачастую используется вместе с sort

Исходный файл:

abc
abc
def
abc
def
def
def

Отброс с сортировкой:

> cat data.txt | sort | uniq
abc
def

Отброс без сортировки:

> cat data.txt | uniq
abc
def
abc
def

Подсчёт количества слов, wc #

Приложение wc предназначено для вычисления статистических харакретистик в файле или потоке данных:

  • Количество слов
  • Количество линий
  • Количество байт
  • Количество символов

Для поиска уникально названных исполняемых файлов из каталогов /bin и /usr/bin можно воспользоваться командой

$ ls /bin /usr/bin | sort | uniq | wc -l
3846

Поиск строк grep #

$ grep --help
Использование: grep [ПАРАМЕТР]… ШАБЛОНЫ [ФАЙЛ]…
Поиск ШАБЛОНОВ в каждом ФАЙЛЕ.
Пример: grep -i 'hello world' menu.h main.c
  • Если grep находит строку, соответствующую шаблону, то он её выводит
  • Если grep не передать файлы для обработки, то он будет обрабатывать данные из стандартного потока ввода
  • Для описания шаблона используются регулярные выражения
> ls /bin /usr/bin | sort | uniq | grep zip
bunzip2
bzip2
bzip2recover
funzip
gpg-zip
gunzip

Начало и конец файла #

Отображение начала файла или потока, head #

Приложение head показывает первые строки файла или стандартного потока ввода

Для управления количеством показываемых линий используется аргумент -n

$ ls /usr/bin | head -n 4
[
411toppm
7z
7za

Отображение конца файла или потока, tail #

Приложение tail показывает последние строки файла или стандартного потока ввода

$ ls /usr/bin | tail -n 4
zipnote
zipsplit
zoom
zsh

Отслеживание изменений в файле #

Некоторые приложения постоянно записывают информацию в файл, например для ведения журнала своей деятельности

Приложение tail позволяет следить за изменениями в файле

tail -f info.log

В одной консоли будем следить за состоянием файла:

$ touch work.log
$ tail -f work.log
abc
def
def
tail: work.log: файл усечён
info

В другой консоли будем изменять данный файл:

$ echo 'abc' > work.log
$ echo 'def' >> work.log
$ echo 'def' >> work.log
$ echo 'info' > work.log

Отведение потока в файл, tee #

Термином tee называется Т-образный отвод трубопровода

Приложение tee принимает данные на стандартный поток ввода, а затем записывает их на стандартный поток вывода и в файл на жёстком диске

Это приложение удобно использовать для отслеживания промежуточного или финального состояния команды, использующей конвееры

$ ls /usr/bin | grep zip | tee -a zip-list | wc -l
21
$ cat zip-list
funzip
gpg-zip
lzip
...

Текстовый процессор awk #

AWK — это инструмент и скриптовый язык, предназначенный для работы с текстовыми документами

  • AWK работает над отдельными строками документа
  • AWK разбивает строки на поля
  • AWK может сопоставлять строки с шаблонами
  • AWK может выполнять действия над подходящими линиями
$ cat workers.txt
Василий менеджер 10000
Иван разработчик 5000
Ира аналитик 5500
Михаил разработчик 5100
Степан аналитик 5400
$ awk '{print $1,$3}' workers.txt
Василий 10000
Иван 5000
Ира 5500
Михаил 5100
Степан 5400

Текстовый редактор sed #

Данный текстовый редактор позволяет выполнять операции над отдельными строками в файле или в потоке данных

$ sed --help
Использование: sed [ПАРАМЕТР]… {только-сценарий-если-нет-другого-сценария} [входной-файл]…
...
$ cat info.txt
linux is great os. unix is opensource. unix is free os.
learn operating system.
linux linux which one you choose.
linux is easy to learn.unix is a multiuser os.Learn unix
$ cat info.txt | sed 's/unix/linux/2'
linux is great os. unix is opensource. linux is free os.
learn operating system.
linux linux which one you choose.
linux is easy to learn.unix is a multiuser os.Learn linux

© A. M. Васильев, 2022, CC BY-SA 4.0, andrey@crafted.su