Перед чтением этой статьи рекомендуем ознакомиться с предыдущими публикациями из серии Основы написания bash-скриптов:
- Знакомство с bash
- Часть 1. Bash-скрипты. Основные команды и рекомендации
- Часть 2. Bash-скрипты. Переменные, комментарии, пользовательский ввод
В третьей статье серии о bash-скриптах мы расскажем, что такое потоки данных в bash, и рассмотрим операторы перенаправления ввода и вывода.
Введение
При работе с оболочкой bash часто требуется передать данные от одной утилиты к другой. Например, можно в одной цепочке команд при помощи grep
найти в каталоге файлы с определённой последовательностью символов, командой mv
в один приём переименовать все эти файлы и переместить в отдельный каталог. Данные между командами передают при помощи операторов перенаправления потоков и управляющих операторов.
В этой статье рассмотрены операторы перенаправления ввода и вывода, в следующей — конвейеры, here-документы и управление заданиями.
Что такое потоки данных в bash
Когда пользователь взаимодействует с компьютером через командную строку, данные делятся на три потока:
- стандартный ввод, stdin;
- стандартный вывод, stdout;
- стандартная ошибка, stderr.
За каждым потоком закреплён идентификатор, называемый файловым дескриптором.
Файловый дескриптор — это системный объект, через который программы ссылаются на файлы или на другие ресурсы (например, конвейеры, устройства или терминалы). Он указывает на источник данных или место их записи.
Название | Значение | Получение или отображение | Номер файлового дескриптора |
stdin | Вводимые данные | Обычно вводится через клавиатуру. Может перенаправляться в другие точки через конвейер. | 0 |
stdout | Выводимые данные | Обычно выводятся в терминал. Могут перенаправляться в другие точки через конвейер. | 1 |
stderr | Диагностические и отладочные сообщения | 2 |
Точки ввода и вывода можно менять, чтобы компьютер получал информацию не со стандартного ввода и выводил не на стандартный вывод. Такое изменение называется перенаправлением.
В следующих разделах будут показаны примеры использования файловых дескрипторов для перенаправления потоков.
Перенаправление вывода >
Оператор > перенаправляет по указанному пути содержимое стандартного вывода команды и сообщений об ошибках. Не все команды генерируют поток stdout: например, у команд sync
, true
и false
, mount
и umount
и многих других он не предусмотрен.
Операторы — спецсимволы или их последовательности, производящие операции с командами, потоком управления, логикой, арифметикой и сравнением строк. Cогласно Руководству GNU по обоочке bash к операторам относят управляющие операторы и операторы перенаправления. Операторы управления — это следующие токены (последовательности символов): перенос строки, ||, &&, &, ;, ;;, |, (, ) и другие. Многие из них мы рассмотрим в статьях этой серии. Операторы перенаправления >, <, >> и другие рассмотрены в этой и следующей статьях. |
Возьмём результат выполнения команды date
:
$ date
Чт 18 апр 2024 14:58:52 +04
Содержимое потока stdout можно перенаправить — например, в файл somedata.txt
(если он не существовал до этого, то будет создан):
$ date > somedata.txt
$ cat somedata.txt
Чт 18 апр 2024 14:58:52 +04
Иногда для изучения хода программы полезно записывать стандартный вывод и ошибки, возникающие в ходе её выполнения, в файл. Для этого используют файловые дескрипторы, о которых говорилось выше:
№ | Команда | Значение |
1 |
| Записать в файл стандартный вывод скрипта |
2 |
| Записать в файл сообщения об ошибках |
3 |
| Записать в один файл стандартный вывод и сообщения об ошибках |
4 |
| Только для bash: записать в один файл стандартный вывод и сообщения об ошибках |
5 |
| Не выводить стандартный вывод и сообщения об ошибках — отправить их на «нулевое устройство» |
С оператором &>
работает только bash, а другие оболочки — например, sh и ksh — нет. Поэтому, если нужно написать как можно более универсальный скрипт, не рекомендуется использовать этот оператор. Но полезно знать его, чтобы узнавать в чужих скриптах.
У оператора >
есть важная особенность: файл, в который записывается стандартный вывод, перезаписывается, то есть его прежнее содержимое удаляется.
Перенаправление вывода с добавлением >>
Оператор >>
добавляет стандартный вывод команды в конце текущего содержимого файла, а не заменяет это содержимое. Например, можно перенаправить вывод команды uname -r
, которая выводит текущую версию ядра Linux, в созданный файл somedata.txt
. Если такого файла нет, он будет создан, как и при работе с оператором >.
$ uname -r >> somedata.txt
$ cat somedata.txt
Чт 18 апр 2024 14:58:52 +06
5.15.0-70-generic
Перенаправлять вывод таким способом можно и в пустой файл, поэтому есть смысл в большинстве случаев использовать перенаправление с добавлением, чтобы не перезаписать случайно нужный файл.
Если нужно добавить стандартный вывод или ошибки программы в уже существующий файл, в упомянутых выше командах нужно использовать оператор >>:
./script.sh 2 >> error_log.txt
Следующая команда выгружает массив данных из определённых столбцов в базе данных СУБД MySQL и сохраняет её в файл customers_100.csv
:
mysql -u lite -p -e "SELECT id, customer_id, first_name, last_name, city, country FROM customers_global ORDER BY id LIMIT 100" --batch --silent -D customers_db | sed 's/\t/,/g' >> customers_100.csv
1) Команда mysql -u lite -p
вызывает клиент командной строки MySQL, указывает имя пользователя и предлагает ему ввести пароль.
2) Часть -e "SELECT id, customer_id, first_name, last_name, city, country FROM customers_global ORDER BY id LIMIT 100"
позволяет выполнить SQL-запрос непосредственно из командной строки.
Смысл запроса:
- оператор SELECT выбирает определенные столбцы
— id, customer_id, first_name, last_name, city, country
— из таблицыcustomers_global
; - оператор
ORDER BY id
упорядочивает результаты по столбцу id в порядке возрастания; - оператор
LIMIT 100
ограничивает вывод первыми 100 строками.
3) Ключ -D customers_db
указывает, какую базу данных использовать.
4) Опция --batch
позволяет выводить данные в формате таблиц, разделённых знаками табуляции — текстовые файлы такого формата проще обрабатывать программными средствами.
Опция --silent
отключает отображение имен столбцов — выводятся только строки с данными.
5) Конвейер перенаправляет вывод предыдущей команды команде sed
.
6) Команда sed 's/\t/,/g'
заменяет все символы табуляции \t
на запятые. Таким образом вывод MySQL преобразуется в формат .csv, то есть comma-separated values — значения, разделённые запятыми.
7) Полученные данные в формате .csv перенаправляются в файл customers_100.csv.
Перенаправление ввода <
Иногда требуется прочитать содержимое файла при помощи определённой программы. Перенаправление ввода позволяет оболочке выполнить команду, используя в качестве источника ввода файл, а не клавиатуру.
Синтаксис в общем виде выглядит так:
команда -опции < файл
Так как команды для обработки файлов принимают их имена в качестве аргументов и без перенаправления, этот оператор чаще всего используется в цепочках из нескольких перенаправлений или конвейеров. При чтении длинных последовательностей команд человеку проще понять, какая программа какой поток принимает, если между ними есть операторы перенаправления.
Например, в одной команде можно использовать перенаправление ввода и вывода:
head -20 < list_100.txt >> list_20.txt
Программа head
принимает на вход содержимое файла list_100.txt
, в котором 100 строк, и отображает первые 20 из них. Эти 20 строк записываются в файл list_20.txt
.
Перенаправление вывода при помощи exec
Если скрипт выполняется долго, удобно переводить его в фоновый режим. Можно сделать это при помощи оператора & (об этом расскажем в следующем разделе Управление заданиями) или запланировать задание для утилиты cron.
Выполняемые в фоне скрипты не имеют доступа к терминалу для отображения вывода, поэтому обычная практика — сохранять stdout таких скриптов в лог, чтобы при необходимости можно было их отладить.
Перенаправление в файл практично и в том случае, если скрипт выводит много информации: так вывод не пропадает, и в дальнейшем его можно просматривать и обрабатывать.
Когда требуется записать потоки скрипта stdout и stderror целиком в файл и не выводить на экран, обычно используется команда exec
:
exec &> log_file.txt
Эта команда действует в отношении всех следующих строк скрипта, а после его завершения прекращает действовать.
Описанный в разделе выше фрагмент с оператором перенаправления > log_file.txt 2>&1
действует только в отношении той команды, после которой добавлен. Для перенаправления в файл полного вывода скрипта этот фрагмент пришлось бы добавлять к каждой команде в скрипте. Поэтому оператор > обычно используют с отдельными командами в терминале или для записи в файл вывода конкретных команд внутри скрипта.
Следующий скрипт mysql_backup_script.sh
запускает резервное копирование базы данных СУБД MySQL и записывает в лог вывод и сообщения об ошибках.
#!/bin/bash
datetime=$(date +"%Y-%m-%d-%H-%M-%S")
db_name="customers_db"
backup_file="/backup/db/${db_name}-${datetime}.sql"
backup_log="/backup/logs/log_${datetime}.log"
backup_options="--routines --triggers --events --single-transaction --quick"
db_username="lite"
export MYSQL_PWD="$SECRET"
mkdir -p /backup/db /backup/logs
exec &>> $backup_log
echo "Запуск задания резервного копирования..."
if mysqldump -u $db_username $backup_options $db_name > $backup_file 2>> $backup_log; then
echo "Резервное копирование успешно завершено."
else
echo "Не удалось выполнить резервное копирование. Чтобы узнать причину, проверьте лог: $backup_log"
exit 1
fi
unset MYSQL_PWD
unset SECRET
echo "Задание завершено $(date)"
Смысл скрипта:
1) Присваиваются значения переменным:
datetime
— вывод компонентов командыdate
(текущей даты): год, месяц, день, часы, минуты, секунды;db_name
— имя копируемой базы данных MySQL;backup_file
— путь к файлу резервной копии, в который включены значения переменныхdb_name
иdatetime
;backup_log
— путь к файлу лога копирования, в который также включены значения переменныхdb_name
иdatetime
;backup_options
— строка с перечнем параметров копирования.
Вот значения этих параметров:
--routines
В резервную копию (дамп) включаются хранимые процедуры и функции вместе с данными и структурой таблиц.
--triggers
Для полного копирования эксплуатационного поведения БД.в дамп включаются триггеры — объекты БД, автоматически выполняющие определённые процедуры при наступлении событий (например, INSERT, UPDATE
и DELETE
).
--events
В дамп включаются выполняемые по расписанию задания из планировщика событий (Event Scheduler) MySQL .
--all-databases
Создается полный дамп экземпляра сервера MySQL, включая созданные пользователями базы данных и системную базу данных MySQL с привилегиями и ролями пользователей.
--single-transaction
Создает целостный снимок базы данных в ходе единой транзакции без блокировки таблиц.
--quick
Указывает mysqldump
получать строки с сервера по одной за раз, а не буферизировать весь набор результатов в памяти. Это повышает производительность и позволяет избежать потенциальных проблем с памятью во время выполнения дампа.
- Переменной
db_username
присваивается значение имени пользователя MySQL —lite
. - Переменной окружения
MYSQL_PWD
, которую MySQL использует для хранения паролей к базам данных, присваивается значение переменной окруженияSECRET
. Это значение будет передано в переменнуюSECRET
непосредственно при запуске скрипта, а затем удалено из окружения. Указывать пароли таким способом безопаснее, чем записывать их непосредственно в скрипте, но тоже не очень надёжно. Рекомендуется пользоваться признанными способами аутентификации: например, плагинами LDAP для MySQL.
2) Команда mkdir
создаёт каталоги /backup/db
и /backup/logs
на случай, если они не существуют.
3) Команда exec
перенаправляет весь последующий стандартный вывод скрипта и сообщения об ошибках в файл, обозначенный переменной backup_log
.
4) Отображается (то есть записывается в лог скрипта) сообщение "Запуск задания резервного копирования...
"
5) Условный оператор if
проверяет:
- Если команда
mysqldump
выполнена успешно и её вывод записан в указанный файл, в лог добавляется сообщение:Резервное копирование успешно завершено.
- Если команду выполнить не удалось, в лог добавляется сообщение:
Не удалось выполнить резервное копирование. Чтобы узнать причину, проверьте лог: <путь к файлу лога>
В этом случае в переменную кода возврата записывается значение 1 — «ошибка».
Код возврата (exit status) — значение, которое дочерний процесс возвращает родительскому в момент завершения. 0 означает успешное завершение процесса, значения от 1 до 255 — завершение с ошибкой. |
6) В лог добавляется сообщение:
Задание завершено <текущая дата>.
7) Значения переменных MYSQL_PWD
и SECRET
удаляются из окружения.
Скрипт запускается следующей командой:
SECRET="somepassword" ./mysql_backup_script.sh
где somepassword
— значение пароля.
Заключение
В этой статье мы рассмотрели несколько видов перенаправлений ввода и вывода в bash. Они позволяют с помощью коротких и ясных команд передавать данные от одной утилиты к другой, ускоряя выполнение операций. В следующей статье расскажем о других способах передачи данных между командами.