Gọi nhiều tập lệnh bash và chạy chúng song song, không theo trình tự


19

Giả sử rằng tôi có ba (hoặc nhiều hơn) các kịch bản bash: script1.sh, script2.sh, và script3.sh. Tôi muốn gọi cả ba kịch bản này và chạy chúng song song . Một cách để làm điều này là chỉ thực hiện các lệnh sau:

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

(Nói chung, các tập lệnh có thể mất vài giờ hoặc vài ngày để hoàn thành, vì vậy tôi muốn sử dụng nohupđể chúng tiếp tục chạy ngay cả khi bảng điều khiển của tôi đóng.)

Nhưng, liệu có cách nào để thực hiện những ba lệnh trong song song với một đơn cuộc gọi?

Tôi đã suy nghĩ một cái gì đó như

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

nhưng điều này dường như thực hiện script1.sh, script2.shscript3.shtheo thứ tự, không song song.


2
"Cuộc gọi duy nhất" có nghĩa là gì?
jw013

1
Trường hợp sử dụng là gì? Bạn có một triệu kịch bản để bắt đầu?
l0b0

@ jw013 Ý tôi là, một cái gì đó giống như một lệnh dòng ngắn. Nếu tôi có 100 tập lệnh để bắt đầu, tôi muốn có thể nhập một cái gì đó ngắn (như nohup bash script{1..100}.sh &hoặc for i in {1..100}; do nohup bash script{1..100} &; done), thay vì nhập nohup bash script*.sh &100 lần khác nhau.
Andrew

1
Trong trường hợp các tập lệnh có đầu ra hữu ích: Bạn cũng có thể khởi động chúng bên trong screen(hoặc tmux), để giải quyết vấn đề bàn điều khiển nhưng vẫn giữ quyền truy cập vào đầu ra (và đầu vào).
Hauke ​​Laging

1
Không có gì ngăn cản bạn gõ cả 3 lệnh đó trong cùng một dòng. nohup ... & nohup ... & nohup ... &. Thay vào đó, nếu bạn muốn chạy tất cả các tập lệnh mà không cần nhập từng tên tập lệnh riêng lẻ, một vòng lặp đơn giản sẽ thực hiện.
jw013

Câu trả lời:



14

Một cách tốt hơn sẽ là sử dụng GNU Parallel . GNU song song là đơn giản và với nó, chúng ta có thể kiểm soát số lượng công việc để chạy song song với nhiều quyền kiểm soát hơn các công việc.

Trong lệnh dưới đây, script{1..3}.shđược mở rộng và được gửi dưới dạng đối số bashsong song. Ở đây -j0chỉ ra rằng càng nhiều công việc nên được chạy càng tốt. Theo mặc định parallelchạy một công việc cho một lõi cpu.

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

Và bạn cũng có thể thử sử dụng

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

Trong khi thực hiện phương thức thứ hai nếu bạn nhận được bất kỳ thông báo lỗi nào thì điều đó có nghĩa là --tolleftùy chọn đó được đặt /etc/parallel/configvà cần phải xóa và mọi thứ sẽ hoạt động tốt.

Bạn có thể đọc GNU Parallelstrang man ở đây để có nhiều lựa chọn phong phú hơn.

Và trong trường hợp nếu bạn đang chạy các công việc từ một máy từ xa, hãy sử dụng tốt hơn screenđể phiên không bị đóng do sự cố mạng. nohuplà không cần thiết, như các phiên bản gần đây của bash là đến với huponexitnhư offvà điều này sẽ ngăn chặn vỏ mẹ gửi HUPtín hiệu để con của nó trong quá trình thoát của nó. Trong trường hợp nếu nó không unset làm điều đó với

$ shopt -u huponexit  

Nếu bạn sẽ sử dụng bashnhư vỏ parallel -j0 bash :::: <(ls script{1..3}.sh)có thể được giảm xuống parallel -j0 bash :::: script{1..3}.sh, không?
iruvar

Không, không, khi '::::' được sử dụng song song, điều đó có nghĩa là đối số là một tệp chứa các lệnh được thực thi và không phải là chính lệnh đó. Ở đây chúng tôi đang sử dụng thay thế quy trình để chuyển hướng tên tập lệnh trong bộ mô tả tệp.
Kannan Mohan

Er .. trong trường hợp đó tại sao không parallel -j0 bash ::: script{1..3}.sh?
iruvar

bash ::: script{1..3}.shđược truyền cho parallel, không phải ::: script{1..3}.sh. Vì vậy, đây đầu tiên nên mở rộng ra parallel bash ::: script1.sh script2.sh script3.shbằng vỏ và sau đó parallellời gọi của bash script1.sh, bash script2.sh, bash script3.sh. Tôi đã thử nó
iruvar

1
Không, tôi không bối rối, tất cả những gì tôi nói là vấn đề của OP được giải quyết tốt hơn parallel -j0 bash ::: script{1..3}.sh- điều này tốt hơn ::::phương pháp vì nó tránh được nhu cầu thay thế quy trình. Ngoài ra phân tích cú pháp đầu ra ls được cưỡi với cạm bẫy
iruvar

9

Chúng ta cũng có thể sử dụng xargsđể chạy song song nhiều tập lệnh.

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

ở đây mỗi tập lệnh được truyền cho bash làm đối số riêng. -P 0chỉ ra rằng số lượng quá trình song song có thể càng nhiều càng tốt. Nó cũng an toàn hơn khi sử dụng bash mặc định job control feature (&).


5

Một giải pháp dòng duy nhất :

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

Ít lịch sự hơn, chỉ cần sử dụng tập lệnh bao bọc:

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

Hoặc lặp qua chúng:

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

2

Nếu bạn đang tìm cách tiết kiệm cho mình một số nỗ lực đánh máy

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

Hoặc trên suy nghĩ thứ hai, có thể không


1

Kiểm tra công cụ này: https://github.com/wagoodman/bashful

Nói rằng bạn có mytasks.yamlvới

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

Và bạn chạy nó như vậy:

nohup bashful run mytasks.yaml

Các tập lệnh của bạn sẽ được chạy song song với thanh tiến trình dọc (+ eta nếu bạn đã chạy nó trước đó và thời gian là xác định). Bạn có thể điều chỉnh số lượng tác vụ bạn muốn chạy song song nếu bạn bắt đầu chạy nhiều hơn chỉ 3 nhiệm vụ đã cho ở đây:

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

Tuyên bố miễn trừ trách nhiệm: Tôi là tác giả.


0

Tôi đang đề xuất một tiện ích đơn giản hơn nhiều tôi vừa viết. Hiện tại nó được gọi là mệnh, nhưng sẽ sớm được đổi tên thành parl hoặc pll, chưa quyết định.

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

API đơn giản như:

par "script1.sh" "script2.sh" "script3.sh"

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.