Memanggil beberapa skrip bash dan menjalankannya secara paralel, bukan secara berurutan

19

Misalkan saya memiliki tiga (atau lebih) script bash: script1.sh, script2.sh, dan script3.sh. Saya ingin memanggil ketiga skrip ini dan menjalankannya secara paralel . Salah satu cara untuk melakukan ini adalah dengan hanya menjalankan perintah berikut:

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

(Secara umum, skrip mungkin membutuhkan beberapa jam atau hari untuk menyelesaikannya, jadi saya ingin menggunakannya nohupagar terus berjalan meskipun konsol saya ditutup.)

Tetapi, adakah cara untuk menjalankan ketiga perintah itu secara paralel dengan satu panggilan?

Saya sedang memikirkan sesuatu seperti

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

tapi ini muncul untuk mengeksekusi script1.sh, script2.shdan script3.shsecara berurutan, tidak secara paralel.

Andrew
sumber
2
Apa arti "panggilan tunggal"?
jw013
1
Apa gunanya? Apakah Anda memiliki sejuta skrip untuk memulai?
l0b0
@ jw013 Maksudku, sesuatu seperti satu perintah baris pendek. Jika saya memiliki 100 skrip untuk memulai, saya ingin dapat mengetikkan sesuatu yang pendek (suka nohup bash script{1..100}.sh &atau for i in {1..100}; do nohup bash script{1..100} &; done), daripada mengetik nohup bash script*.sh &100 kali yang berbeda.
Andrew
1
Seandainya skrip memiliki output yang berguna: Anda dapat memulai di dalamnya screenjuga (atau tmux), untuk menyelesaikan masalah konsol tetapi tetap mengakses output (dan input).
Hauke ​​Laging
1
Tidak ada yang mencegah Anda mengetik semua 3 perintah di baris yang sama. nohup ... & nohup ... & nohup ... &. Jika Anda bermaksud mengatakan bahwa Anda ingin menjalankan semua skrip tanpa mengetik setiap nama skrip secara terpisah, sebuah loop sederhana akan melakukannya.
jw013

Jawaban:

16
for((i=1;i<100;i++)); do nohup bash script${i}.sh & done
Hauke ​​Laging
sumber
2
Anda melewatkan tanda kurung dekat.
David Conrad
1
@ HaukeLaging Bagaimana jika nama skrip berbeda?
Patrick
14

Cara yang lebih baik adalah dengan menggunakan GNU Parallel . Paralel GNU sederhana dan dengan itu kita dapat mengontrol jumlah pekerjaan yang dijalankan secara paralel dengan lebih banyak kontrol atas pekerjaan.

Dalam perintah di bawah ini, script{1..3}.shdiperluas dan dikirim sebagai argumen bashsecara paralel. Di sini -j0menunjukkan bahwa sebanyak mungkin pekerjaan harus dijalankan. Secara default parallelmenjalankan satu pekerjaan untuk satu inti cpu.

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

Dan Anda juga dapat mencoba menggunakan

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

Saat menjalankan metode kedua jika Anda mendapatkan pesan kesalahan maka itu berarti bahwa --tollefopsi diatur /etc/parallel/configdan yang perlu dihapus dan semuanya akan berfungsi dengan baik.

Anda dapat membaca GNU Parallelshalaman manual di sini untuk opsi yang lebih kaya.

Dan jika Anda menjalankan pekerjaan dari mesin jarak jauh, lebih baik gunakan screenagar sesi tidak ditutup karena masalah jaringan. nohuptidak perlu, seperti versi terbaru dari bash sebagai datang dengan huponexitsebagai offdan ini akan mencegah orang tua shell mengirimkan HUPsinyal kepada anak-anak selama keluarnya. Dalam kasus jika tidak disetel lakukan dengan

$ shopt -u huponexit  
Kannan Mohan
sumber
Jika Anda akan menggunakan bashshell yang parallel -j0 bash :::: <(ls script{1..3}.sh)dapat dikurangi parallel -j0 bash :::: script{1..3}.sh, bukan?
iruvar
Tidak itu tidak, ketika '::::' digunakan dengan paralel itu berarti bahwa argumen adalah file yang berisi perintah yang akan dieksekusi dan bukan perintah itu sendiri. Di sini kita menggunakan substitusi proses untuk mengarahkan ulang nama skrip ke dalam deskriptor file.
Kannan Mohan
Er .. kalau begitu kenapa tidak parallel -j0 bash ::: script{1..3}.sh?
iruvar
Sudah bash ::: script{1..3}.shditeruskan ke parallel, bukan ::: script{1..3}.sh. Jadi ini pertama harus memperluas untuk parallel bash ::: script1.sh script2.sh script3.sholeh shell dan kemudian paralleldoa dari bash script1.sh, bash script2.sh, bash script3.sh. Saya mencobanya
iruvar
1
Tidak, saya tidak bingung, semua yang saya nyatakan adalah bahwa masalah OP lebih baik diselesaikan parallel -j0 bash ::: script{1..3}.sh- ini lebih baik daripada ::::pendekatan karena menghindari kebutuhan untuk proses substitusi. Juga parsing ls output sarat dengan jebakan
Iruvar
9

Kita juga bisa menggunakan xargsuntuk menjalankan banyak skrip secara paralel.

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

di sini setiap skrip diteruskan ke bash sebagai argumen secara terpisah. -P 0menunjukkan bahwa jumlah proses paralel dapat sebanyak mungkin. Lebih aman menggunakan bash default job control feature (&).

Yaalie
sumber
5

Solusi jalur tunggal :

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

Dengan kurang cerdik, cukup gunakan skrip wrapper:

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

Atau lewati mereka:

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

Jika Anda ingin menghemat usaha mengetik

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

Atau pada pikiran kedua, mungkin tidak

iruvar
sumber
1

Lihat alat ini: https://github.com/wagoodman/bashful

Katakanlah Anda sudah mytasks.yamlbersama

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

Dan Anda menjalankannya seperti ini:

nohup bashful run mytasks.yaml

Skrip Anda akan dijalankan secara paralel dengan bilah kemajuan vertikal (+ eta jika Anda sudah menjalankannya sebelumnya dan waktunya sudah pasti). Anda dapat mengubah berapa banyak tugas yang ingin Anda jalankan secara paralel jika Anda mulai menjalankan lebih dari 3 yang diberikan di sini:

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

Penafian: Saya penulis.

Wagmanman
sumber
0

Saya menyarankan utilitas yang jauh lebih sederhana yang baru saja saya tulis. Saat ini disebut par, tetapi akan segera diganti nama menjadi parl atau pll, belum memutuskan.

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

API sesederhana:

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