Chamando vários scripts bash e executando-os em paralelo, não em sequência

19

Suponha que eu tenho três (ou mais) scripts bash: script1.sh, script2.sh, e script3.sh. Gostaria de chamar todos esses três scripts e executá-los em paralelo . Uma maneira de fazer isso é apenas executar os seguintes comandos:

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

(Em geral, os scripts podem levar várias horas ou dias para serem concluídos, portanto, eu gostaria de usá-los nohuppara que continuem sendo executados mesmo que meu console seja fechado.)

Mas, existe alguma maneira de executar esses três comandos em paralelo com uma única chamada?

Eu estava pensando em algo como

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

mas isso parece executar script1.sh, script2.she script3.shem sequência, não em paralelo.

Andrew
fonte
2
O que significa "chamada única"?
jw013
11
Qual é o caso de uso? Você tem um milhão de scripts para iniciar?
precisa saber é o seguinte
@ jw013 Quero dizer, algo como um único comando de linha curta. Se eu tiver 100 scripts para iniciar, gostaria de poder digitar algo curto (como nohup bash script{1..100}.sh &ou for i in {1..100}; do nohup bash script{1..100} &; done), em vez de digitar nohup bash script*.sh &100 vezes diferentes.
Andrew
11
Caso os scripts possuam saída útil: Você também pode iniciá-los dentro screen(ou tmux) para resolver o problema do console, mas manter o acesso à saída (e entrada).
Hauke Laging
11
Não há nada que impeça você de digitar todos os 3 desses comandos na mesma linha. nohup ... & nohup ... & nohup ... &. Se você quer dizer que deseja executar todos os scripts sem digitar cada nome de script individualmente, um loop simples fará isso.
jw013

Respostas:

16
for((i=1;i<100;i++)); do nohup bash script${i}.sh & done
Hauke ​​Laging
fonte
2
Está faltando um parêntese próximo.
David Conrad
11
@HaukeLaging E se os nomes dos scripts forem diferentes?
317 Patrick
14

Uma maneira melhor seria usar o GNU Parallel . O paralelo GNU é simples e, com ele, podemos controlar o número de trabalhos a serem executados em paralelo, com mais controle sobre os trabalhos.

No comando abaixo, script{1..3}.sh é expandido e enviado como argumento para bashem paralelo. Aqui -j0indica que o maior número possível de trabalhos deve ser executado. Por padrão, parallelexecuta um trabalho para um núcleo de CPU.

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

E você também pode tentar usar

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

Ao executar o segundo método, se você receber alguma mensagem de erro, significa que a --tollefopção está definida /etc/parallel/confige que precisa ser excluída e tudo funcionará bem.

Você pode ler GNU Parallels página de manual aqui para obter opções mais ricas.

E, se você estiver executando os trabalhos em uma máquina remota, use melhor screenpara que a sessão não seja fechada devido a problemas de rede. nohupnão é necessário, já que as versões recentes do festa como vindo com huponexitquanto offe isso vai impedir shell pai de envio de HUPsinal para os seus filhos durante a sua saída. Caso não esteja desmarcado, faça-o com

$ shopt -u huponexit  
Kannan Mohan
fonte
Se você vai usar bashcomo o shell parallel -j0 bash :::: <(ls script{1..3}.sh)pode ser reduzido para parallel -j0 bash :::: script{1..3}.sh, não?
Iruvar
Não, não, quando '::::' é usado em paralelo, significa que o argumento é um arquivo que contém comandos a serem executados e não o próprio comando. Aqui estamos usando a substituição de processo para redirecionar os nomes de script em um descritor de arquivos.
Kannan Mohan
Er .. nesse caso, por que não parallel -j0 bash ::: script{1..3}.sh?
Iruvar
Está bash ::: script{1..3}.shsendo passado para parallel, não ::: script{1..3}.sh. Portanto, este deve primeiro expandir para parallel bash ::: script1.sh script2.sh script3.shpelo shell e, em seguida, parallelinvocações de bash script1.sh, bash script2.sh, bash script3.sh. Eu tentei
iruvar 22/11/14
11
Não, não estou confuso, tudo o que afirmo é que o problema do OP é melhor resolvido parallel -j0 bash ::: script{1..3}.sh- isso é melhor do que a ::::abordagem, pois evita a necessidade de substituição de processo. Também analisar saída de ls é montado com armadilhas
Iruvar
9

Também podemos usar xargspara executar vários scripts em paralelo.

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

aqui cada script é passado para o bash como argumento separadamente. -P 0indica que o número de processos paralelos pode ser o máximo possível. Também é mais seguro usar o bash default job control feature (&).

Yaalie
fonte
5

Uma solução de linha única :

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

Com menos facilidade, basta usar um script de wrapper:

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

Ou faça um loop sobre eles:

for script in dir/*.sh
do
    nohup bash "$script" &
done
l0b0
fonte
2

Se você deseja economizar algum esforço de digitação

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

Ou pensando melhor, talvez não

iruvar
fonte
1

Faça o checkout desta ferramenta: https://github.com/wagoodman/bashful

Diga que você tem mytasks.yamlcom

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

E você executa assim:

nohup bashful run mytasks.yaml

Seus scripts seriam executados em paralelo com uma barra de progresso vertical (+ eta se você o executou antes e o tempo é determinístico). Você pode ajustar quantas tarefas deseja executar em paralelo se começar a executar mais do que apenas as três aqui fornecidas:

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

Disclaimer: Eu sou o autor.

wagoodman
fonte
0

Estou sugerindo um utilitário muito mais simples que acabei de escrever. Atualmente, é chamado de par, mas será renomeado em breve para parl ou pll, ainda não decidido.

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

API é tão simples quanto:

par "script1.sh" "script2.sh" "script3.sh"
Kostiantyn Rybnikov
fonte