При работе с оболочкой 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 | command > 1 > log.txt | Записать в файл стандартный вывод скрипта |
2 | command > 2 > error_log.txt | Записать в файл сообщения об ошибках |
3 | command > process.log 2>&1 | Записать в один файл стандартный вывод и сообщения об ошибках |
4 | command &> log.txt | Только для bash: записать в один файл стандартный вывод и сообщения об ошибках |
5 | command > /dev/null 2>&1 | Не выводить стандартный вывод и сообщения об ошибках — отправить их на «нулевое устройство» /dev/null |
С оператором &> работает только 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.csv1) Команда 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. Они позволяют с помощью коротких и ясных команд передавать данные от одной утилиты к другой, ускоряя выполнение операций. В следующей статье расскажем о других способах передачи данных между командами.
Автор статьи: Клара Суботэ