Сценарий в листинге Б.3 демонстрирует, как распараллелить заданную команду по нескольким процессам, выполняющимся одновременно.
Если ваш компьютер оснащен одноядерным процессором или выбранная программа работает медленно по другим причинам, например из-за невысокой скорости доступа к жесткому диску, запуск сразу нескольких экземпляров программы только ухудшит производительность. Будьте осторожны, не запускайте слишком много процессов, так как это легко может застопорить маломощную систему. К счастью, даже Raspberry Pi имеет несколько ядер!
Код
Листинг Б.3. Сценарий bulkrun
··#!/bin/bash
··# bulkrun — выполняет обход файлов в каталоге и запускает несколько
··#·· процессов для их одновременной обработки.
··printHelp()
··{
····echo "Usage: $0 −p 3 −i inputDirectory/ −x \"command −to run/\""
····echo −e "\t-p The maximum number of processes to start concurrently"
····echo −e "\t-i The directory containing the files to run the command on"
····echo −e "\t-x The command to run on the chosen files"
····exit 1
··}
··while getopts "p: x: i: " opt
··do
····case "$opt" in
······p) procs="$OPTARG"····;;
······x) command="$OPTARG"··;;
······i) inputdir="$OPTARG";;
······?) printHelp··········;;
····esac
··done
··if [[-z $procs || −z $command || −z $inputdir]]
··then
····echo "Invalid arguments"
····printHelp
··fi
··total=$(ls $inputdir | wc −l)
··files="$(ls −Sr $inputdir)"
··for k in $(seq 1 $procs $total)
··do
····for i in $(seq 0 $procs)
····do
······if [[$((i+k)) −gt $total]]
······then
········wait
········exit 0
······fi
······file=$(echo "$files" | sed $(expr $i + $k)"q;d")
······echo "Running $command $inputdir/$file"
······$command "$inputdir/$file"&
····done
····wait
··done
Как это работает
Сценарий bulkrun принимает три аргумента: максимальное количество процессов, действующих в каждый конкретный момент времени , каталог с файлами для обработки и команду для запуска (в конец которой добавляется имя файла для обработки) . После чтения пользовательских аргументов с помощью getopts сценарий убеждается в наличии всех трех обязательных аргументов. Если любая из переменных −procs, command или inputdir — осталась неопределенной, сценарий выводит сообщение об ошибке , текст справки и завершает выполнение.
После проверки переменных, необходимых для управления запуском параллельных процессов, сценарий приступает к выполнению фактической работы. Для начала определяется количество обрабатываемых файлов , и их список сохраняется для дальнейшего использования. Затем сценарий входит в цикл for, который следит за количеством файлов, обработанных к текущему моменту. Команда seq используется для организации итераций по всем файлам с шагом, равным максимальному числу процессов, которые могут выполняться параллельно.
Внутри находится еще один цикл for , который следит за количеством процессов, запущенных к данному моменту. Этот внутренний цикл также использует команду seq для организации итераций от 0 до максимального числа процессов с шагом, по умолчанию равным 1. В каждой итерации внутренний цикл for извлекает новый файл из списка , вызывая sed, чтобы вывести только требуемое имя файла из списка, сохраненного в начале сценария, и запускает указанную команду с этим файлом в фоновом режиме с применением знака &.
После запуска максимального количества процессов сценарий вызывает команду wait , которая приостанавливает его выполнение до момента, когда завершатся все команды, запущенные в фоновом режиме. После того как wait завершится, вновь начинается процедура запуска процессов для обработки остальных файлов. Она похожа на процедуру выбора лучшей программы сжатия в сценарии bestcompress (сценарий № 34 в главе 4).
Запуск сценария