Вызов нескольких сценариев bash и запуск их параллельно, а не последовательно

19

Предположим , что у меня есть три (или более) Баш сценариев: script1.sh, script2.shи script3.sh. Я хотел бы вызвать все три сценария и запустить их параллельно . Один из способов сделать это - просто выполнить следующие команды:

nohup bash script1.sh &
nohup bash script2.sh &
nohup bash script3.sh &

(Как правило, выполнение сценариев может занять несколько часов или дней, поэтому я хотел бы использовать их, nohupчтобы они продолжали работать, даже если моя консоль закрывается.)

Но есть ли способ выполнить эти три команды параллельно с одним вызовом?

Я думал что-то вроде

nohup bash script{1..3}.sh &

но это, кажется, выполняется script1.sh, script2.shи script3.shпоследовательно, а не параллельно.

Андрей
источник
2
Что означает «один звонок»?
jw013
1
Какой вариант использования? У вас есть миллион сценариев для запуска?
l0b0
@ jw013 Я имею в виду что-то вроде короткой строки. Если у меня есть 100 сценариев для запуска, я хотел бы иметь возможность набирать что-то короткое (например, nohup bash script{1..100}.sh &или for i in {1..100}; do nohup bash script{1..100} &; done), а не печатать nohup bash script*.sh &100 раз.
Андрей
1
В случае, если у скриптов есть полезный вывод: Вы можете запустить их screenтоже (или tmux), чтобы решить проблему с консолью, но сохранить доступ к выводу (и вводу).
Хауке Лагинг
1
Ничто не мешает вам набрать все 3 команды в одной строке. nohup ... & nohup ... & nohup ... &, Если вместо этого вы имеете в виду, что хотите запускать все сценарии, не вводя имя каждого сценария по отдельности, простой цикл сделает это.
jw013

Ответы:

16
for((i=1;i<100;i++)); do nohup bash script${i}.sh & done
Хауке Лагинг
источник
2
Вам не хватает близких скобок.
Дэвид Конрад
1
@HaukeLaging Что если имена сценариев отличаются?
Патрик
14

Лучшим способом было бы использовать GNU Parallel . Параллельная GNU проста, и с ее помощью мы можем контролировать количество параллельных заданий, обеспечивая больший контроль над заданиями.

В приведенной ниже команде script{1..3}.shраскрывается и отправляется в качестве аргументов bashпараллельно. Здесь -j0указывает, что необходимо выполнить как можно больше заданий. По умолчанию parallelвыполняется одно задание для одного ядра процессора.

$ parallel -j0 bash :::: <(ls script{1..3}.sh)

И вы также можете попробовать использовать

$ parallel -j0 bash ::: script{1..3}.sh

При выполнении второго метода, если вы получаете какое-либо сообщение об ошибке, это означает, что --tollefопция установлена, /etc/parallel/configи ее нужно удалить, и все будет работать нормально.

Вы можете прочитать GNU Parallelsсправочную страницу здесь для более богатых вариантов.

А в случае, если вы выполняете задания с удаленной машины, лучше использовать, screenчтобы сессия не закрывалась из-за проблем с сетью. nohupВ этом нет необходимости, поскольку последние версии bash поставляются с huponexitas, offи это не позволит родительской оболочке отправлять HUPсигнал своим дочерним элементам во время выхода. В случае, если это не сброшено, сделайте это с

$ shopt -u huponexit  
Каннан Мохан
источник
Если вы собираетесь использовать bashв качестве оболочки parallel -j0 bash :::: <(ls script{1..3}.sh)можно уменьшить parallel -j0 bash :::: script{1..3}.sh, нет?
iruvar
Нет, это не так, когда '::::' используется параллельно, это означает, что аргумент - это файл, который содержит команды для выполнения, а не сама команда. Здесь мы используем подстановку процессов для перенаправления имен скриптов в дескрипторе файлов.
Каннан Мохан,
Эээ .. в таком случае почему бы и нет parallel -j0 bash ::: script{1..3}.sh?
Ирувар
Это bash ::: script{1..3}.shпередается parallel, а не ::: script{1..3}.sh. Таким образом , это должно первым расширяться parallel bash ::: script1.sh script2.sh script3.shоболочкой и затем parallelпризываний bash script1.sh, bash script2.sh, bash script3.sh. Я попробовал это
iruvar
1
Нет, я не смущен, все, что я утверждаю, это то, что проблема ОП решается лучше parallel -j0 bash ::: script{1..3}.sh- это лучше, чем ::::подход, поскольку он устраняет необходимость замены процесса. Также парсинг вывода ls
связан
9

Мы также можем использовать xargsдля параллельного запуска нескольких скриптов.

$ ls script{1..5}.sh|xargs -n 1 -P 0 bash

здесь каждый скрипт передается bash как аргумент отдельно. -P 0указывает, что количество параллельных процессов может быть как можно больше. Также безопаснее использовать bash по умолчанию job control feature (&).

Yaalie
источник
5

Одна линия решение:

$ nohup bash script1.sh & nohup bash script2.sh & nohup bash script3.sh &

Менее остроумно, просто используйте скрипт-обертку:

$ cat script.sh
#!/usr/bin/env bash
script1.sh &
script2.sh &
script3.sh &
$ nohup script.sh &

Или зациклите их:

for script in dir/*.sh
do
    nohup bash "$script" &
done
l0b0
источник
2

Если вы хотите сэкономить на печати

eval "nohup bash "script{1..3}.sh" &"

Или, если подумать, может и нет

Iruvar
источник
1

Оформить заказ этого инструмента: https://github.com/wagoodman/bashful

Скажем, у вас есть mytasks.yamlс

tasks:
    - name: A title for some tasks
      parallel-tasks:
        - cmd: ./script1.sh
        - cmd: ./script2.sh -x an-arg
        - cmd: ./script3.sh -y some-other-arg

И вы запускаете это так:

nohup bashful run mytasks.yaml

Ваши сценарии будут выполняться параллельно с вертикальным индикатором выполнения (+ это, если вы запускали его раньше, а время детерминировано). Вы можете настроить количество задач, которые вы хотите запускать параллельно, если вы начнете выполнять больше, чем только 3 из приведенных здесь:

config:
    max-parallel-commands: 6
tasks:
    ...

Отказ от ответственности: я автор.

wagoodman
источник
0

Я предлагаю гораздо более простую утилиту, которую я только что написал. В настоящее время он называется par, но скоро будет переименован в parl или pll, еще не решил.

https://github.com/k-bx/par

API так же прост, как:

par "script1.sh" "script2.sh" "script3.sh"
Константин Рыбников
источник