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

LinuxBeginner
Практиковаться сейчас

Введение

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

В этой лабораторной работе вы будете использовать стандартный ввод, стандартный вывод и стандартную ошибку. Вы узнаете, когда > перезаписывает содержимое, а когда >> добавляет данные в конец, как 2> и 2>&1 обрабатывают ошибки, как канал передаёт данные, как tee одновременно отображает и сохраняет один и тот же вывод, а также в каких случаях полезен /dev/null.

Изучите стандартный ввод, вывод и ошибку

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

Каждая команда начинает работу с тремя стандартными потоками:

Дескриптор Название Подключение по умолчанию
0 стандартный ввод, или stdin клавиатура
1 стандартный вывод, или stdout терминал
2 стандартная ошибка, или stderr терминал

Создайте рабочую папку и перейдите в неё:

mkdir -p /home/labex/project/streams-lab
cd /home/labex/project/streams-lab

Создайте входной файл из трёх строк с помощью here-документа. Оболочка передаёт строки между двумя маркерами EOF команде cat, а оператор > сохраняет вывод cat в input.txt:

cat > input.txt <<'EOF'
alpha
beta
gamma
EOF

Обычно команда cat input.txt получает имя файла в качестве аргумента. Оператор < вместо этого подключает файл к дескриптору 0, то есть к стандартному вводу:

cat < input.txt

На экране должны появиться три строки. Используйте такое же перенаправление ввода с командой wc -l, которая подсчитывает количество строк:

wc -l < input.txt

В выводе должно быть 3. Поскольку имя файла не передаётся команде wc как аргумент, выводится только число.

Перенаправьте и добавьте данные в стандартный вывод

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

Убедитесь, что вы находитесь в рабочей папке потоков:

cd /home/labex/project/streams-lab

Оператор > подключает дескриптор 1, то есть стандартный вывод, к файлу. Перед записью он создаёт файл или удаляет содержимое существующего файла:

echo "Stream report" > report.txt
cat report.txt

Выполните ещё одну перезапись и убедитесь, что предыдущая строка исчезла:

echo "Input lines: 3" > report.txt
cat report.txt

Теперь используйте >>, который открывает файл назначения в режиме добавления:

echo "Status: complete" >> report.txt
cat report.txt

В файле должны находиться ровно две строки: Input lines: 3, а затем Status: complete. Оболочка выполняет перенаправление до запуска команды.

Разделите стандартный вывод и стандартную ошибку

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

Следующая команда ls получает один существующий путь и один отсутствующий путь:

cd /home/labex/project/streams-lab
ls -l input.txt missing.txt

Строка с описанием input.txt относится к stdout. Сообщение No such file or directory относится к stderr. По умолчанию оба потока отображаются в терминале, но это разные потоки.

Перенаправьте дескриптор 1 с помощью >, а дескриптор 2 — с помощью 2>:

ls -l input.txt missing.txt > listing.log 2> errors.log

Команда по-прежнему возвращает ненулевой код завершения, поскольку один путь отсутствует, но оболочка остаётся готовой принять следующую команду. Просмотрите файлы назначения:

cat listing.log
cat errors.log

В listing.log должна быть информация о input.txt без сообщения об ошибке. В errors.log должны быть указаны missing.txt и сообщение об ошибке, но не должно быть успешного списка.

Объедините стандартный вывод и стандартную ошибку

На этом шаге вы направите stdout и stderr в один журнал и узнаете, почему важен порядок перенаправлений.

Сначала перенаправьте stdout в combined.log, а затем направьте дескриптор 2 туда же, куда в данный момент направлен дескриптор 1:

cd /home/labex/project/streams-lab
ls -l input.txt missing.txt > combined.log 2>&1

Выражение 2>&1 означает: «направить дескриптор 2 туда же, куда в данный момент направлен дескриптор 1». Поскольку > combined.log указано первым, оба потока попадут в файл.

cat combined.log

В файле должны содержаться и сведения о input.txt, и сообщение об ошибке для missing.txt.

Bash также поддерживает &> как сокращённую запись для перенаправления обоих потоков:

ls -l report.txt absent.txt &> shorthand.log
cat shorthand.log

Во втором файле должны находиться успешный список для report.txt и сообщение об ошибке для absent.txt. Переносимая форма > file 2>&1 особенно часто используется в сценариях и командах запуска служб.

Просматривайте и сохраняйте вывод конвейера с помощью tee

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

Канал, обозначаемый символом |, подключает stdout команды слева к stdin команды справа. Отсортируйте входной файл в обратном алфавитном порядке:

cd /home/labex/project/streams-lab
sort -r input.txt

При обычном перенаправлении вывода отсортированные строки записываются в файл и больше не отображаются в терминале:

sort -r input.txt > sorted.txt
cat sorted.txt

Команда tee копирует данные из stdin одновременно в stdout и в указанный файл. Выполните ту же сортировку через канал:

sort -r input.txt | tee sorted.txt

На экране должны появиться отсортированные строки, а sorted.txt должен получить это же содержимое. По умолчанию tee перезаписывает файл назначения так же, как >.

Опция -a переводит tee в режим добавления. Добавьте ещё одну строку и одновременно отобразите её:

echo "delta" | tee -a sorted.txt
cat sorted.txt

Теперь в файле должны находиться gamma, beta, alpha и delta. tee полезна, когда нужно одновременно видеть текущий вывод в терминале и сохранять журнал.

Отбрасывайте ненужные данные с помощью Dev Null

На этом шаге вы намеренно отбросите один поток с помощью /dev/null, сохраните полезный вывод через tee и очистите существующий журнал.

/dev/null — это специальное устройство, которое принимает и отбрасывает всё записанное в него. Выведите содержимое одного существующего и одного отсутствующего каталога, отбрасывая только stderr:

cd /home/labex/project/streams-lab
ls -l . missing-directory 2> /dev/null

Вы должны увидеть список каталога, но не сообщение об ошибке для missing-directory. Объедините это с tee, чтобы видимый stdout также сохранялся:

ls -l . missing-directory 2> /dev/null | tee visible-listing.log

Канал передаёт только stdout. stderr был отдельно перенаправлен в /dev/null до того, как данные поступили в канал.

Просмотрите сохранённый список:

cat visible-listing.log

Наконец, создайте временный журнал, содержимое которого можно удалить, а затем используйте /dev/null как пустой источник ввода, чтобы очистить файл. Отдельный файл сохраняет данные об объединённых потоках из шага 4:

echo "outdated scratch data" > scratch.log
cat /dev/null > scratch.log

Проверьте размер файла:

ls -l scratch.log

Файл должен по-прежнему существовать, а его размер должен составлять 0 байт. Используйте отбрасывание данных осознанно: скрытые ошибки могут усложнить поиск неисправностей, когда диагностическая информация действительно нужна.

Итоги

Вы потренировались работать с тремя стандартными потоками и их файловыми дескрипторами, подключали файлы к stdin с помощью < и перенаправляли stdout с помощью > и >>. Вы разделяли stderr с помощью 2>, объединяли его со stdout с помощью 2>&1 и &>, а также узнали, почему важен порядок операторов.

Кроме того, вы сравнили обычное перенаправление в файл с конвейерами и tee, использовали tee -a для добавления данных с одновременным отображением вывода и отбрасывали ненужные данные с помощью /dev/null. Эти приёмы помогут вам в дальнейшем изучать журналы, фоновые команды и сценарии оболочки.