Перед чтением этой статьи рекомендуем ознакомиться с предыдущими из серии Основы написания bash-скриптов:
- Знакомство с bash
- Часть 1. Bash-скрипты. Основные команды и рекомендации
- Часть 2. Bash-скрипты. Переменные, комментарии, пользовательский ввод
- Часть 3. Bash-скрипты. Перенаправление ввода и вывода
В этой статье рассмотрим дополнительные способы управлять взаимодействием между командами bash и выполнением команд:
Управление заданиями
В каждый конкретный момент на переднем плане (foreground) находится только один процесс Linux. С ним можно взаимодействовать при помощи клавиатуры, и он выводит на экран выходной поток (если stdout предусмотрен и выводится в терминал, а не перенаправляется).
Остальные запущенные процессы выполняются в фоне (background). Они не связаны с терминалом — не выводят на него данные и не получают их с клавиатуры.
При помощи оболочки bash можно переключаться между процессами, переводя требуемые в фон либо на передний план. В контексте такого переключения запущенные пользователем процессы называются заданиями.
Например, удобно переводить в фон длительные процессы — в том числе и команды, соединённые операторами перенаправления. Для этого в конце команды ставят амперсанд &
.
Следующая команда создаёт архив каталога /home/lite и перенаправляет его стандартный вывод в файл, а затем переводит процесс в фоновый режим:
tar -czf /backup/home-lite.tar.gz /home/lite > /backup/logs/tar-home-lite-backup.log 2>&1 &
1) Команда tar
создаёт (ключ -c
) при помощи программы gzip
(-z
) файл (-f
) /backup/home-lite.tar.gz
— архив каталога /home/lite
.
2) Оператор >
перенаправляет вывод команды tar
в файл лога.
3) Выражение 2>&1
перенаправляет сообщения об ошибках в поток stdout.
4) Оператор &
в конце команды переводит выполнение в фоновый режим.
Выводимый результат:
[1] 77612
Здесь [1]
— ID задания, 77612
— ID процесса (PID).
ID задания (job ID) присваивает оболочка bash, когда оператор &
переводит процесс в фоновый режим. PID — идентификатор процесса в операционной системе.
Список всех запущенных процессов (включая их PID) всех пользователей и используемые ими системные ресурсы можно просмотреть этой командой:
ps -aux
Команды управления заданиями
Можно переводить в фоновый режим несколько команд последовательно — вторую, пока не выполнена первая, и так далее. Заданиями в списке можно управлять при помощи следующих команд:
1) jobs
— вывести список фоновых заданий:
[1]+ Running tar -czf /backup/home-lite.tar.gz /home/lite > backup/logs/tar-home-lite-backup.log 2>&1
2) fg %1
— вывести задание с ID=1 из фонового режима.
Задание будет выведено на передний план и будет занимать терминал до завершения выполнения.
3) Ctrl+Z
, затем bg %1
— приостановить выполнение задания и перевести его в фоновый режим.
4) kill %1
— завершить выполнение команды;
kill -9 %1
— принудительно завершить выполнение команды.
Here-документы
Here-документ (HereDoc) — это фрагмент кода или текста из нескольких строк, передаваемый на вход другим командам и программам. Оболочка bash работает с ним как с файлом.
Here-документы полезны при перенаправлении сразу нескольких команд, так как структурируют скрипт и упрощают его чтение для человека.
Общий вид синтаксиса:
команда << ограничитель
строка 1
строка 2
ограничитель
Here-документы работают с любыми командами, принимающими перенаправление.
Дефис после оператора перенаправления <<-
позволяет игнорировать табуляцию в теле документа.
Ограничитель в первой строке — маркер начала here-документа. Чаще всего используют EOF
или EOL
, но подойдет любое слово (согласно определению в рамке ниже) длиной от одного символа, которое отсутствует в теле документа — например, цифра или спецсимвол. Ограничителем в начале here-документа может быть и экранированный метасимвол — тогда в конце документа этот метасимвол не требуется экранировать.
Слово (согласно Руководству GNU по оболочке bash) — последовательность символов, воспринимаемая оболочкой как единое целое. Слова не могут содержать метасимволов, не заключённых в кавычки. Метасимволы (согласно тому же Руководству) — символы, которые разделяют слова, если используются без кавычек. К ним относятся: пробел, знак табуляции, перенос строки и следующие символы: |, &, ;, (, ), < и >. |
Если в документе нужно выполнить подстановку команд и переменных, ограничитель в первой строке указывают без кавычек. Если требуется игнорировать подстановку, ограничитель в первой строке заключают в двойные кавычки или экранируют символом \.
Тело here-документа содержит любое количество строк (завершающихся переносом строки) с командами, переменными, строковыми литералов и других входных данных.
В последней строке указывают тот же ограничитель, что в первой, всегда без кавычек.
В следующем скрипте here-документы используются при соединении с удалённым сервером по протоколу SSH для изменения пароля пользователя СУБД MySQL:
#!/bin/bash
remote_user="lite"
remote_host="somehost"
mysql_user="mylite"
new_password="betterpassword"
ssh $remote_user@$remote_host << EOF
mysql -u root -p'somesecurepassword' << EOL
ALTER USER '$mysql_user'@'localhost' IDENTIFIED BY '$new_password';
FLUSH PRIVILEGES;
EOL
EOF
Скрипт выполняет следующие действия:
1) Присваиваются значения переменным.
remote_user
означает пользователя на удалённом сервере,remote_host
— удалённый сервер,mysql_user
— пользователя СУБД MySQL на удалённом сервере,new_password
— новый пароль.
2) Команда ssh
запускает сеанс связи пользователя с удалённым сервером. Этой команде перенаправляется содержимое here-документа, который начинается с ограничителя EOF
.
4) Тело here-документа — вход пользователя root
в СУБД MySQL при помощи команды mysql
. Ей, в свою очередь, перенаправляется содержимое следующего here-документа, который начинается с ограничителя EOL.
5) Внутри второго документа команда ALTER USER
изменяет пароль пользователя с именем, которое содержится в переменной mysql_user
, на значение переменной new_password
.
6) Команда FLUSH PRIVILEGES
обновляет таблицы привилегий (прав) пользователей MySQL.
7) Конец второго документа обозначается ограничителем EOL
, конец первого — ограничителем EOF
.
Here strings
Here strings (here-строки) — разновидность here-документов для передачи слов (последовательностей символов согласно определению в предыдущем разделе) на стандартный вход команд.
Это означает, что если в here-строке есть метасимволы, нужно заключить её в кавычки целиком или экранировать метасимволы.
Here strings не имеют ограничителей в начале и конце.
Синтаксис в общем виде выглядит так:
команда <опции> <<< слово
Этот вид перенаправления удобен для быстрой проверки команд или скриптов, не требующих большого объёма входных данных.
Следующая команда считает количество слов в передаваемой ей строке:
wc -w <<< "The word undergoes tilde expansion, parameter and variable expansion, command substitution, arithmetic expansion, and quote removal."
Выводимый результат:
16
От команд echo
или cat
тоже можно быстро перенаправить строку какой-либо команде через конвейер.
Любая из двух следующих команд:
echo "ТЕКСТ, НАБРАННЫЙ ПРОПИСНЫМИ БУКВАМИ" | tr [A-Z] [a-z]
или
tr [A-Z] [a-z] <<< "ТЕКСТ, НАБРАННЫЙ ПРОПИСНЫМИ БУКВАМИ"
выведет на экран такой результат:
текст, набранный прописными буквами
При этом here-строки проще читать человеку, так как в них нет дополнительных элементов помимо принимающей команды, оператора перенаправления и передаваемой строки. Поэтому в большинстве случаев для перенаправления команде короткой строки стоит выбирать here strings.
Конвейер
Конвейер (pipeline, пайп), обозначаемый символом вертикальной черты | — это механизм межпроцессного взаимодействия, который направляет стандартный вывод и иногда стандартную ошибку одного процесса на стандартный ввод другого. Таким образом команды можно соединять в последовательности и быстро выполнять многоступенчатую обработку данных из командной строки или в скриптах.
Согласно Руководству GNU по оболочке bash конвейер относится к управляющим операторам.
Общий вид синтаксиса:
команда 1 | команда 2
В разделе Перенаправление ввода с добавлением >> статьи Перенаправление ввода и вывода показан пример выгрузки массива данных из базы данных MySQL и его конвертации в формат .csv.
Если потребовалось отобразить строки этого массива в другом порядке и в формате, который удобен для чтения, а не для машинной обработки, но в данный момент нельзя сделать повторную выгрузку этого массива, то можно получить нужное отображение при помощи bash:
column -s, -t customers_100.csv | sort -k4 | less -S
Эта команда выполняет следующие действия:
1.Программа column
читает содержимое файла customers_100.csv
и отображает его в удобочитаемом для человека виде — разделяет столбцы пробелами в нужных количествах, а не запятыми.
2. Cодержимое по конвейеру | направляется команде sort
, которая по ключу -k4
упорядочивает строки по содержимому четвёртого столбца, то есть по фамилиям — фамилии упорядочиваются от A к Z:
3. Упорядоченное содержимое по конвейеру передаётся команде less
, чтобы на экране не отображались все столбцы сразу, а можно было прокручивать таблицу при помощи клавиш «влево» и «вправо».
Конвейер можно использовать в одной команде с перенаправлениями разных видов:
команда1 | команда2 | команда3 > файл_с_результатом
Например:
df -h | grep '/dev/sda1' | awk '{print $5}' > sda1_usage.txt
Смысл команды:
- Отобразить объём занятого дискового пространства по файловым системам.
- Найти строку с фрагментом
'/dev/sda1'.
- Вырезать из неё пятый столбец —
Use%
(Занятое пространство в %). - Записать содержимое столбца
Use%
в файлsda1_usage.txt
.
Опция pipefail
По умолчанию код возврата (значение, которое дочерний процесс возвращает родительскому в момент завершения) конвейера равен коду возврата последней команды — ошибки предыдущих команд скрыты.
Назначение следующей команды — найти в файле /var/log/nginx/error.log
слово error и отобразить только 3 и 5 столбцы в найденных строках:
grep error /var/log/nginx/error.log | awk '{print $3, $5}'
Выводимый результат:
grep: /var/log/nginx/error.log: No such file or directory
Команда grep
выполнена с ошибкой — файл с указанным именем не найден (лог ошибок веб-сервера NGINX по умолчанию называется error_log
). На выход этой команды и на вход awk
передаётся пустая строка.
Тем не менее, команда awk
принимает эту строку как валидный ввод и возвращает код возврата 0:
echo $? # Показать код возврата команды
0
Опция pipefail
, включённая перед запуском конвейера, изменяет это поведение:
set -o pipefail
grep error /var/log/nginx/error.log | awk '{print $3, $5}'
Тогда, если в цепочке с конвейерами завершится ошибкой не последняя команда — в данном случае grep
— код возврата будет ненулевым:
echo $?
2
Код возврата 2 для команды grep
означает, что файл отсутствует или нет прав на его чтение. (Ошибка 1 означает, что указанную последовательность символов не удалось найти.)
Опция pipefail
особенно полезна в скриптах и длинных цепочках команд. Вместе с функцией set -e
она позволяет прерывать выполнение скрипта сразу после возникновения ошибки в одной из команд конвейера.
Заключение
В этой статье мы рассмотрели дополнительные способы передавать данные между командами — конвейер и here-документы, а также узнали, как переключаться между заданиями в оболочке bash. Используя эти приёмы, вы можете упростить передачу и обработку входных и выходных данных между программами и ускорить выполнение задач.