Как запускать команды параллельно в Bash
Привет, коллега! Надеюсь, ты выжил после выходных и не сорвал спину на мероприятии по копке картофеля. Сегодня у нас с тобой Bash.
читать первым в телеграм читать первым в макс
Мы прекрасно знаем, что bash-скрипты выполняются последовательно. Но есть ли способы запускать команды параллельно?
Конечно, есть, сейчас про это и поговорим. Покажу два способа, как это можно легко осуществить. Первый способ основан на символе &.
Пишем подопытный скрипт:
#!/bin/bash
sleep 5 && echo "sleep 5_1" &
sleep 5 && echo "sleep 5_2" &
wait
echo "sleep 0"
Здесь первая и вторая команды запустятся параллельно. Через 5 секунд на экран выведутся 3 строчки: sleep 5_1, sleep 5_2 и sleep 0.
Оболочка ждёт (wait), пока завершатся два предыдущих процесса, прежде чем запустить следующую команду. Получается, всё то, что в скрипте идёт после wait, будет в режиме ожидания, пока не завершится первый sleep и второй.
Теперь давай запустим в терминале последовательно такие команды:
sleep 60 &
sleep 90 &
sleep 120 &
На экран выведутся записи вроде таких:
[1] 38161
[2] 38166
[3] 38167
Это PID процессов, которые ты запустил в фоновом режиме. Но интересует нас тут другое. А именно команда jobs.
Запускаем jobs и смотрим:
[1] Done sleep 60
[2]- Running sleep 90 &
[3]+ Running sleep 120 &
Опа! А это список команд, которые мы запустили в фоне. Первое задание завершилось, остальное ещё шуршит. Некий мониторинг из коробки.
Давай теперь напишем более наглядный пример, где всё это можно применить.
downloader(){
wget -q "$1"
}
while IFS= read -r url
do
downloader "$url" &
done < urls.txt
wait
echo "Downloaded complete"
- Скрипт читает построчно файл url.txt.
- Передаёт каждую строчку в функцию downloader.
- Функция downloader каждый раз запускается в фоне.
- Происходит скачивание файла по ссылке.
- По завершении (wait) получаем
компливитcomplete.
Файл url.txt представляет собой список прямых URL на файлы, которые нужно скачать.
Получается, мы не дожидаемся, пока скачается первый файл, а сразу скачиваем всё пачкой. Мультизагрузка.
Если совсем уж по-простому, то символ & говорит — запусти всё одновременно и параллельно. Типа такого, с таким ты уже всяко встречался:
hostname & date & uname &
Тут всё запустится одновременно, и порядок вывода на экран будет каждый раз свой. Всё зависит от того, с какой скоростью отработает команда.
Есть ещё такая утилита parallel, устанавливается, как и всё остальное: apt/yum/brew install parallel.
Делает она то же самое, но имеет более гибкие настройки через параметры. Например, предыдущий пример со скачиванием файлов мог бы выглядеть таким образом:
parallel -j 4 wget -q {} < urls.txt
Ключ -j означает, сколько джобов будет запараллелено, что-то типа потоков/threads.
Углубляться сейчас в parallel особого смысла не вижу, но для общего кругозора ты про неё должен знать. Иногда бывает, что для решения задачи подойдёт именно parallel, а не нативка с &.
Ну и на закуску есть такая штука $!, она позволяет узнать PID последнего запущенного процесса. Давай на примере, запускай:
sleep 60 &
[1] 39032
echo $!
39032
В первой команде запустили фоном ожидание 60 секунд, вывелся порядковый номер джобы и PID. Ну а чтобы получить последний PID, выполняем третью команду с $!. На экран вывелся PID в чистом виде, а дальше можешь его сохранить в переменную и уже проверять в скрипте, завершился он или нет.
Вот так это и работает. Ничего сложного. Надеюсь, было интересно. Хорошего тебе понедельника, увидимся!
