Как обрабатывать последовательность элементов по N за раз

Вопрос или проблема

Я хочу запустить команду N раз параллельно, используя bash и xargs на системе Linux. Команда выглядит так:

for i in `seq 1 $(howmany.txt)`; do aprogramm --file file$i.dat ; done

Файл howmany.txt содержит значение 100, а ntimes.txt содержит значение 5.

Файлы file1 до file100 существуют, последовательно от 1 до 100, и я хочу обрабатывать их по 5 раз параллельно. Как я могу сделать это с помощью xargs?

Вместо того чтобы писать сценарий для выполнения команд, напишите сценарий, который выводит команды:

for i in `seq 1 $(howmany.txt)`
  do echo "aprogramm --file file$i.dat"
done

Каждая строка этого вывода должна быть корректным синтаксисом команды для выбранного вами интерпретатора команд.

Как только вывод будет выглядеть хорошо, передайте его в parallel(1) с опцией -j5, чтобы запустить 5 заданий параллельно:

for i in `seq 1 $(howmany.txt)`
  do echo "aprogramm --file file$i.dat"
done | parallel -j5

В показанном вами коде есть несколько проблем. Во-первых, $(howmany.txt) будет пытаться выполнить howmany.txt. Если это исполняемый сценарий, находящийся в вашем PATH, который выводит число, тогда это может сработать, но если это просто текстовый файл с числом, вам нужно использовать $(cat howmany.txt). Во-вторых, лучше использовать $( command ) вместо `seq` для большей ясности и возможности вложения команд.

С учетом этого, чтобы сделать это с помощью xargs, вам нужно что-то вроде:

seq 1 $(< howmany.txt) | xargs -I {} -n1 -P $(< ntimes.txt) aprogramm --file file{}.dat

На самом деле, это работа для GNU parallel:

parallel -j ntimes.txt aprogramm --file file{} < howmany.txt

Или, если все ваши файлы называются fileN и вы хотите обработать все fileN (так что вам на самом деле не нужен howmany.txt), то вы можете сделать:

parallel -j ntimes.txt aprogramm --file {} ::: file*

Одно из многих преимуществ parallel перед xargs заключается в том, что вы можете изменить число в howmany.txt во время выполнения, чтобы увеличить или уменьшить количество работающих заданий.

Для обработки файлов пакетами используйте xargs -n. Если в пакет обрабатывается один файл, используйте 1:

echo file*.dat | xargs -n1

Чтобы обрабатывать их параллельно, используйте -P.

echo file*.dat | xargs -n1 -P$(< ntimes.txt) aprogramm --file

Предположения:

  • файлы howmany.txt и ntimes.txt гарантированно содержат одно целое число и ничего больше
  • в каталоге могут быть другие файлы, которые мы не хотим обрабатывать (например, простой find . -name 'file*.dat' может вернуть больше файлов, чем необходимо)

Для демонстрационных целей:

$ cat aprogram
#!/bin/bash

echo "input: $@"
sleep 3

$ cat howmany.txt
10

$ cat ntimes.txt
4

Одна идея с использованием метода Джима для вывода списка имен файлов, переданных в xargs:

read -r max   < howmany.txt
read -r count < ntimes.txt

for ((i=1; i<=max; i++))
do
    echo "file$i.dat"
done | xargs -r -n1 -P "$count" ./aprogram --file

Это генерирует:

input: --file file1.dat        # 4 вызова подряд
input: --file file2.dat
input: --file file3.dat
input: --file file4.dat
                               # 3 сек задержки
input: --file file5.dat        # 4 вызова подряд
input: --file file6.dat
input: --file file7.dat
input: --file file8.dat
                               # 3 сек задержки
input: --file file9.dat        # последние 2 вызова подряд
input: --file file10.dat
                               # 3 сек задержки

Ответ или решение

Конечно! Давайте детально разберем, как вы можете обрабатывать файлы с использованием команды xargs и запустить команду N раз параллельно в Bash на системе Linux.

Исходные данные

У вас есть файл howmany.txt, который содержит число 100, и файл ntimes.txt, содержащий число 5. Вы хотите выполнить команду aprogramm --file file{i}.dat для каждой из файлов от file1.dat до file100.dat, обрабатывая 5 файлов одновременно.

Шаги для решения задачи

  1. Обработка содержимого файлов:
    Вам нужно сначала считать количество файлов для обработки и количество параллельных процессов из указанных текстовых файлов. Это можно сделать с помощью команды read.

  2. Генерация списка файлов:
    Для создания списка файлов в формате file{i}.dat, где i — это число от 1 до 100, можно использовать цикл.

  3. Использование xargs:
    Мы будем использовать xargs для запуска вашей программы одновременно для N файлов.

Пример скрипта

Вот пример Bash-скрипта, который решает вашу задачу:

#!/bin/bash

# Читаем значения из файлов
read -r max < howmany.txt
read -r count < ntimes.txt

# Генерируем список файлов и передаем в xargs
for ((i=1; i<=max; i++))
do
    echo "file$i.dat"
done | xargs -r -n1 -P "$count" aprogramm --file

Объяснение кода

  1. Чтение значений:

    • read -r max < howmany.txt: считывает максимальное число файлов.
    • read -r count < ntimes.txt: считывает количество параллельных процессов.
  2. Генерация списка:

    • С помощью цикла for мы генерируем имена файлов от file1.dat до file100.dat и передаем их в стандартный вывод.
  3. Параллельное выполнение команды:

    • Используя xargs с флагом -n1, мы говорим xargs обрабатывать по одному элементу за раз.
    • Флаг -P "$count" указывает количество параллельных процессов, которое мы считаем из файла ntimes.txt.
    • aprogramm --file — это команда, которую мы хотим выполнить для каждого сгенерированного имени файла.

Дополнительные рекомендации

  • Убедитесь, что скрипт aprogramm существует и имеет права на выполнение.
  • Запустите скрипт в соответствующей директории, где находятся файлы, чтобы получить правильные результаты.
  • Поскольку xargs будет работать параллельно, вы можете увидеть одновременное выполнение команд, что может помочь сократить общее время обработки.

Таким образом, вы сможете эффективно обрабатывать файлы несколько раз параллельно, используя Bash и xargs. Если у вас возникнут дополнительные вопросы или понадобится помощь в настройки вашего скрипта, не стесняйтесь спрашивать!

Оцените материал
Добавить комментарий

Капча загружается...