Chạy nhiều lệnh và giết chúng như một trong bash


52

Tôi muốn chạy nhiều lệnh (quy trình) trên một shell. Tất cả đều có đầu ra liên tục và không dừng lại. Chạy chúng trong nền nghỉ Ctrl- C. Tôi muốn chạy chúng như một quy trình duy nhất (subshell, có thể?) Để có thể ngăn chặn tất cả chúng với Ctrl- C.

Để cụ thể, tôi muốn chạy thử nghiệm đơn vị với mocha(chế độ xem), chạy máy chủ và chạy một số tiền xử lý tệp (chế độ xem) và xem đầu ra của mỗi trong một cửa sổ đầu cuối. Về cơ bản tôi muốn tránh sử dụng một số nhiệm vụ chạy.

Tôi có thể nhận ra nó bằng cách chạy các tiến trình trong nền ( &), nhưng sau đó tôi phải đặt chúng vào nền trước để ngăn chặn chúng. Tôi muốn có một quy trình để bọc chúng và khi tôi dừng quá trình thì nó dừng lại là 'trẻ em'.


Họ nên chạy đồng thời hay cái khác?
Minix

Có, các quy trình nên chạy đồng thời, nhưng tôi cần xem đầu ra từ mỗi.
dùng1876909

Câu trả lời:


67

Để chạy các lệnh đồng thời, bạn có thể sử dụng &dấu tách lệnh.

~$ command1 & command2 & command3

Điều này sẽ bắt đầu command1, sau đó chạy nó trong nền. Tương tự với command2. Sau đó, nó bắt đầu command3bình thường.

Đầu ra của tất cả các lệnh sẽ được cắt xén cùng nhau, nhưng nếu đó không phải là vấn đề với bạn, đó sẽ là giải pháp.

Nếu bạn muốn có một cái nhìn riêng về đầu ra sau này, bạn có thể dẫn đầu ra của từng lệnh vào tee, cho phép bạn chỉ định một tệp để phản chiếu đầu ra.

~$ command1 | tee 1.log & command2 | tee 2.log & command3 | tee 3.log

Đầu ra có thể sẽ rất lộn xộn. Để chống lại điều đó, bạn có thể cung cấp cho đầu ra của mỗi lệnh một tiền tố bằng cách sử dụng sed.

~$ echo 'Output of command 1' | sed -e 's/^/[Command1] /' 
[Command1] Output of command 1

Vì vậy, nếu chúng ta kết hợp tất cả những thứ đó lại với nhau:

~$ command1 | tee 1.log | sed -e 's/^/[Command1] /' & command2 | tee 2.log | sed -e 's/^/[Command2] /' & command3 | tee 3.log | sed -e 's/^/[Command3] /'
[Command1] Starting command1
[Command2] Starting command2
[Command1] Finished
[Command3] Starting command3

Đây là một phiên bản lý tưởng hóa cao của những gì bạn có thể sẽ thấy. Nhưng đó là điều tốt nhất tôi có thể nghĩ ra ngay bây giờ.

Nếu bạn muốn dừng tất cả chúng cùng một lúc, bạn có thể sử dụng bản dựng trong trap.

~$ trap 'kill %1; kill %2' SIGINT
~$ command1 & command2 & command3

Điều này sẽ thực thi command1command2trong nền và command3ở nền trước, cho phép bạn giết nó bằng Ctrl+ C.

Khi bạn giết tiến trình cuối cùng với Ctrl+ Ccác kill %1; kill %2lệnh được thực thi, bởi vì chúng tôi đã kết nối thực thi của chúng với việc nhận SIGnal INTerupt, điều được gửi bằng cách nhấn Ctrl+ C.

Chúng lần lượt giết quá trình nền thứ 1 và thứ 2 (của bạn command1command2). Đừng quên gỡ bẫy, sau khi bạn sử dụng xong các lệnh của mình trap - SIGINT.

Hoàn thành quái vật của một lệnh:

~$ trap 'kill %1; kill %2' SIGINT
~$ command1 | tee 1.log | sed -e 's/^/[Command1] /' & command2 | tee 2.log | sed -e 's/^/[Command2] /' & command3 | tee 3.log | sed -e 's/^/[Command3] /'

Tất nhiên, bạn có thể nhìn vào màn hình . Nó cho phép bạn chia bàn điều khiển của bạn thành nhiều bảng điều khiển riêng biệt như bạn muốn. Vì vậy, bạn có thể theo dõi tất cả các lệnh riêng biệt, nhưng cùng một lúc.


3
Mong tất cả những lời chỉ trích. :)
Minix

2
Cảm ơn bạn. Nó thực hiện chính xác những gì tôi muốn (lệnh bẫy). Các giải pháp phải được gói trong một kịch bản cho tái sử dụng mặc dù.
dùng1876909

@ user1876909 Đây là bộ xương. Các chi tiết cụ thể tùy thuộc vào bạn [1]. Mừng vì tôi có thể giúp. [1] pastebin.com/jKhtwF40
Minix

3
Đây là một giải pháp khá thông minh, iv đã học được một điều mới, bravo +1
mike-m

1
Thật đáng kinh ngạc. Tôi có rất nhiều điều để tìm hiểu và học hỏi từ câu trả lời này.
ccnokes

20

Bạn có thể dễ dàng tiêu diệt một loạt các quy trình cùng một lúc nếu bạn sắp xếp để chạy chúng (và chỉ chúng) trong cùng một nhóm quy trình .

Linux cung cấp tiện ích setsidđể chạy một chương trình trong một nhóm quy trình mới (thậm chí trong một phiên mới, nhưng chúng tôi không quan tâm đến điều đó). (Điều này có thể thực hiện được nhưng phức tạp hơn mà không có setsid.)

ID nhóm quy trình (PGID) của nhóm quy trình là ID quy trình của quy trình gốc ban đầu trong nhóm. Để tiêu diệt tất cả các quy trình trong một nhóm quy trình, chuyển âm bản của PGID sang killlệnh hoặc lệnh hệ thống. PGID vẫn còn hiệu lực ngay cả khi quy trình ban đầu với PID này bị chết (mặc dù nó có thể hơi khó hiểu).

setsid sh -c 'command1 & command2 & command3' &
pgid=$!
echo "Background tasks are running in process group $pgid, kill with kill -TERM -$pgid"

Nếu bạn chạy các quy trình trong nền từ trình bao không tương tác , thì tất cả chúng sẽ vẫn nằm trong nhóm quy trình của trình bao. Chỉ trong các vỏ tương tác mà các quy trình nền chạy trong nhóm quy trình riêng của chúng. Do đó, nếu bạn rẽ nhánh các lệnh từ một vỏ không tương tác vẫn còn ở phía trước, Ctrl+ Csẽ giết tất cả chúng. Sử dụng waitnội trang để tạo shell chờ tất cả các lệnh thoát.

sh -c 'command1 & command2 & command3 & wait'
# Press Ctrl+C to kill them all

2
câu trả lời không giới hạn (phương pháp ở phía dưới). Đơn giản để hiểu và ghi nhớ.
Nicolas Marshall

14

Tôi ngạc nhiên khi điều này chưa có ở đây, nhưng cách làm yêu thích của tôi là sử dụng các lớp con với các lệnh nền. Sử dụng:

(command1 & command2 & command3)

Đầu ra có thể nhìn thấy từ cả hai, tất cả các lệnh bash và tiện ích vẫn có sẵn, và một lệnh Ctrl-cgiết tất cả chúng. Tôi thường sử dụng điều này để bắt đầu một máy chủ tệp khách hàng gỡ lỗi trực tiếp và máy chủ phụ trợ cùng một lúc, vì vậy tôi có thể giết cả hai một cách dễ dàng khi tôi muốn.

Cách thức hoạt động của nó là như vậy command1command2đang chạy trong nền của một thể hiện của lớp con mới và command3nằm ở phía trước của cá thể đó, và lớp con là thứ đầu tiên nhận được tín hiệu tiêu diệt từ một Ctrl-cphím bấm. Nó rất giống với việc chạy một tập lệnh bash đối với người sở hữu quy trình nào và khi các chương trình nền bị giết.


Nếu bạn thêm waitlàm lệnh cuối cùng (lệnh 3 trong ví dụ của bạn), bạn có thể thực thi mã sạch sau khi người dùng nhấn Ctrl-c.
dotnetCarpenter

0

Bạn có thể sử dụng dấu chấm phẩy ;hoặc &&như thế này:

cmd1; cmd2   # Runs both the commands, even if the first one exits with a non-zero status.

cmd1 && cmd2 # Only runs the second command if the first one was successful.

Điều đó không chạy các lệnh đồng thời.
Gilles 'SO- ngừng trở nên xấu xa'

-2

Bạn có thể sử dụng một pipe. Điều này sẽ bắt đầu các lệnh ở hai đầu của ống cùng một lúc. Bạn cũng có thể dừng tất cả các lệnh CTRL-C.

1st command | 2nd command | 3rd command

Nếu bạn muốn chạy từng lệnh một, bạn có thể sử dụng phương thức của @ serenesat.


Điều này chuyển đầu ra của lệnh đầu tiên sang lệnh thứ hai (vân vân), không phù hợp ở đây vì đầu ra của lệnh đầu tiên được cho là kết thúc trên thiết bị đầu cuối.
Gilles 'SO- ngừng trở nên xấu xa'
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.