Ускорить сценарий bash, запустив несколько экземпляров цикла for

У меня есть этот скрипт:

 for i in `find ! -newermt "2016-02-13" -name "*svgz"`; do
  inkscape --verb FitCanvasToDrawing --verb FileSave --verb FileClose ${i} --verb FileQuit
done

который ждет, пока inkscape завершит свою работу, а затем перезапустит его со следующим файлом. Я бы хотел, чтобы четыре экземпляра inkscape работали параллельно, чтобы ускорить процесс (у меня есть ~ 5000 файлов для обработки). Это возможно, и если да, то как? Заранее спасибо!

3 ответа

Решение

Попробуйте GNU Parallel.

sudo aptitude install parallel

Я не использовал его некоторое время, но его командная строка должна быть похожа на приведенную ниже:

find ! -newermt "2016-02-13" -name "*svgz" | \
  parallel -j4 \
    inkscape \
    --verb FitCanvasToDrawing \
    --verb FileSave \
    --verb FileClose {} \
    --verb FileQuit

где 4 - количество процессов, которые вы хотите запустить в любой момент времени.

Вы можете использовать GNU параллельно, как объяснялось здесь, для очень похожего вопроса, также включающего inkscape: https://stackoverflow.com/questions/26572397/how-to-process-20k-svg-files-with-inkscape-cli-mode-align-and-merge-objects

Еще один простой трюк, который я использовал сам недавно:

  1. Создайте сценарий "process.sh", обрабатывающий один файл, переданный ему в качестве аргумента.
  2. Сохранить результат команды поиска в текстовом файле

  3. Разбейте файл с помощью команды "split" на столько заданий, сколько вы хотите запустить параллельно.

  4. Запустите несколько экземпляров process.sh, передав ему аргументы через сгенерированные файлы split и xargs.

Вот как я бы подошел к этому. Поскольку у меня нет одинаковых файлов, приведенный ниже пример кода призван открыть 4 текстовых файла с gedit,

Как это работает? Ну, во-первых, мы находим файлы в жестко запрограммированном месте, где они могут храниться (FILEPATH переменная). Затем мы передаем это while read состав. Обратите внимание на использование -print0 а также IFS= read -d'', Это очень часто встречается в программировании на bash для устранения проблемных имен файлов, которые содержат пробелы, непечатаемые символы и т. Д.

каждый gedit file & звонки gedit быть отсоединенным от сценария с &, Это делает пока цикл продолжается без остановки.

То, что делает остановку цикла, является переменной COUNT. Как только мы посчитаем от 0 до некоторого числа, делимого на 4, MOD переменная, которая вычисляется из оператора модуля, станет 0. Теперь оболочка будет ждать всплывающее окно (которое zenity), чтобы подтвердить нерест еще 4 окна. Таким образом, мы считаем 4 раза, сбрасываем переменную, продолжаем.

Единственным недостатком здесь является то, что find не сортирует файлы, поэтому они не обязательно будут в указанном порядке. Если порядок имеет значение, для кода потребуются дополнительные инструкции. В противном случае этого достаточно.

#!/bin/bash

FILEPATH="/home/xieerqi/MYTEXTFILES"
COUNT=0

find $FILEPATH -type f -name "*.txt" -print0 | \
while IFS= read -d ''  FILE;
do
    gedit $FILE & 
    COUNT=$(( $COUNT+1 ))
    MOD=$(( $COUNT % 4 ))

    if [ $MOD -eq 0   ]
    then 
        zenity --question --text "Open 4 more files?"  || exit
    fi
done
Другие вопросы по тегам