Ctrl-C với hai lệnh đồng thời trong bash


15

Tôi muốn chạy hai lệnh đồng thời trong bash trên máy Linux. Vì vậy, trong ./execute.shkịch bản bash của tôi, tôi đặt:

command 1 & command 2
echo "done"

Tuy nhiên, khi tôi muốn dừng tập lệnh bash và nhấn Ctrl+ C, chỉ có lệnh thứ hai được dừng lại. Lệnh đầu tiên tiếp tục chạy. Làm thế nào để tôi chắc chắn rằng tập lệnh bash hoàn chỉnh bị dừng lại? Hoặc trong mọi trường hợp, làm thế nào để tôi dừng cả hai lệnh? Bởi vì trong trường hợp này, bất kể tôi có thường xuyên nhấn Ctrl+ Clệnh tiếp tục chạy và tôi buộc phải đóng thiết bị đầu cuối.


Đặt câu hỏi tiếp theo thành một câu hỏi riêng biệt và xóa ở đây. Bây giờ không rõ ràng cho một khách truy cập nếu cả hai câu hỏi đã được trả lời, hoặc chỉ là câu hỏi nội bộ.
Zelda

Câu trả lời:


17

Nếu bạn gõ

command 1 & command 2

cái này bằng

command 1 &
command 2

tức là điều này sẽ chạy lệnh đầu tiên trong nền và sau đó chạy lệnh thứ hai ở nền trước. Đặc biệt điều này có nghĩa là, echo "done"bản in của bạn được in sau khi command 2hoàn thành ngay cả khi command 1vẫn đang chạy.

Bạn có thể muốn

command 1 &
command 2 &
wait
echo "done"

Điều này sẽ chạy cả hai lệnh trong nền và chờ cho cả hai hoàn thành.


Nếu bạn nhấn CTRL-C, điều này sẽ chỉ gửi tín hiệu SIGINT đến quá trình tiền cảnh, tức là command 2trong phiên bản của bạn hoặc waittrong phiên bản của tôi.

Tôi sẽ đề nghị đặt một cái bẫy như thế này:

#!/bin/bash

trap killgroup SIGINT

killgroup(){
  echo killing...
  kill 0
}

loop(){
  echo $1
  sleep $1
  loop $1
}

loop 1 &
loop 2 &
wait

Với bẫy, tín hiệu SIGINT do CTRL-C tạo ra bị bẫy và được thay thế bởi killgroupchức năng, nó sẽ giết chết tất cả các quá trình đó.


Cảm ơn về câu trả lời của bạn! Tuy nhiên tôi có một câu hỏi tiếp theo. Bây giờ tôi có đoạn script sau: bẫy killgroup SIGINT killgroup () {echo kill ... kill 0} lệnh001 lệnh1 & lệnh2 Tôi đã sử dụng lệnh chờ vì tập lệnh được phép tiếp tục khi lệnh 2 kết thúc. Tuy nhiên, dường như lệnh 1 đã bắt đầu khi tôi chạy tập lệnh. Tôi có thể sửa cái này không? Cảm ơn
maero21

lệnh1 bắt đầu trực tiếp sau khi lệnh001 kết thúc. bạn có thể sử dụng set -xở đầu tập lệnh của mình để in các lệnh được thực thi.
michas

6

Khi đặt lệnh vào nền từ tập lệnh, PID không được hiển thị trên màn hình. Bạn có thể sử dụng biến dựng sẵn $!lưu trữ PID của quá trình cuối cùng để bạn có thể nắm bắt được PID của lệnh1.

command1 &
echo $!

sẽ lặp lại PID của lệnh1.

Bash cũng cung cấp tích hợp bẫy mà bạn có thể sử dụng để đăng ký một chuỗi các lệnh để chạy khi nhận được tín hiệu cụ thể. Bạn có thể sử dụng điều này để bắt SIGINT và giết lệnh1 trước khi thoát khỏi tập lệnh chính, vd

#!/bin/bash

onINT() {
echo "Killing command1 $command1PID too"
kill -INT "$command1PID"
exit
}

trap "onINT" SIGINT
command1 &
command1PID="$!"
comamnd2
echo Done

Bây giờ, trong khi lệnh 2 đang chạy, việc nhấn Ctrl Csẽ khiến cả lệnh1 và lệnh2 được gửi SIGINT.


Bạn cũng có thể sử dụng %ncú pháp để tiêu diệt các công việc nền cụ thể trong trình bao này. Thông thường bạn phát hành kill %1để giết quá trình nền mới nhất và duy nhất. Với nhiều quá trình nền, sử dụng jobsđể xem danh sách đầu tiên.
9000

@ 9000: Có nhưng OP đang chạy các lệnh của họ trong một tập lệnh (./execute.sh) vì vậy việc nhận công việc có hiệu quả hơn nhiều không?

@lain: chắc chắn rồi. Tôi đã bỏ lỡ quan điểm về việc chạy từ một kịch bản.
9000

5

Các phiên bản mới hơn của GNU Parallel sẽ làm những gì bạn muốn:

parallel ::: "command 1" "command 2"
echo "done"

Hoặc nếu commandvẫn giữ nguyên:

parallel command ::: 1 2
echo done

Xem video giới thiệu để được giới thiệu nhanh: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

Đi qua hướng dẫn (manallel_tutorial). Bạn dòng lệnh với tình yêu bạn cho nó.


1

Ctrl+ Cgửi tín hiệu SIGINT đến quy trình trước của bạn command2. command1được chạy trong nền, do đó không liên quan đến luồng đầu vào.

Khi bạn nhập command1 &, bash sẽ cung cấp cho bạn quy trình 'PID, đại loại như thế [1234]. Để giết quá trình này, bạn có thể sử dụng kill 1234. Bây giờ, nếu bạn có các PID của cả hai command1command2(hãy xem ps -ef), bạn có thể sử dụng killđể chấm dứt tất cả:

kill pid1 pid2 pid3 ...

Một mẹo nhỏ sẽ là chạy cả hai lệnh trong nền, với:

command1 & command2 &

Bash sẽ cung cấp cho bạn cả hai PID, sẵn sàng để bị giết. Một mẹo khác là mang về command1tiền cảnh một khi bạn đã giết command2:

command1 & command2
# Hit Ctrl+C : command2 terminates.

fg # Bring back command1 to foreground.
# Hit Ctrl+C again, command1 terminates.

Thông tin thêm có sẵn ở đây: http://linuxg.net/how-to-manage-background-and-forground- Processes /

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.