Ctrl-C dengan dua perintah simultan di bash

15

Saya ingin menjalankan dua perintah secara bersamaan di bash pada mesin Linux. Karenanya dalam ./execute.shskrip bash saya, saya meletakkan:

command 1 & command 2
echo "done"

Namun ketika saya ingin menghentikan skrip bash dan menekan Ctrl+ C, hanya perintah kedua yang dihentikan. Perintah pertama terus berjalan. Bagaimana cara memastikan bahwa skrip bash lengkap dihentikan? Atau bagaimana pun, bagaimana cara menghentikan kedua perintah? Karena dalam kasus ini tidak peduli seberapa sering saya menekan Ctrl+ Cperintah tetap berjalan dan saya terpaksa menutup terminal.

maero21
sumber
Buat pertanyaan tindak lanjut menjadi pertanyaan terpisah dan hapus di sini. Sekarang tidak jelas bagi pengunjung apakah kedua pertanyaan itu dijawab, atau hanya pertanyaan awal.
Zelda

Jawaban:

17

Jika Anda mengetik

command 1 & command 2

ini sama dengan

command 1 &
command 2

yaitu ini akan menjalankan perintah pertama di latar belakang dan kemudian menjalankan perintah kedua di latar depan. Terutama ini berarti, bahwa Anda echo "done"dicetak setelah command 2selesai walaupun command 1masih berjalan.

Anda mungkin mau

command 1 &
command 2 &
wait
echo "done"

Ini akan menjalankan kedua perintah di latar belakang dan menunggu keduanya selesai.


Jika Anda menekan CTRL-C ini hanya akan mengirim sinyal SIGINT ke proses latar depan, yaitu command 2di versi Anda atau waitdi versi saya.

Saya sarankan memasang perangkap seperti ini:

#!/bin/bash

trap killgroup SIGINT

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

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

loop 1 &
loop 2 &
wait

Dengan jebakan, sinyal SIGINT yang dihasilkan oleh CTRL-C terperangkap dan diganti oleh killgroupfungsinya, yang membunuh semua proses itu.

michas
sumber
Terima kasih atas jawaban Anda! Namun saya punya pertanyaan lanjutan. Saya sekarang memiliki skrip berikut: trap killgroup SIGINT killgroup () {echo kill ... kill 0} command001 command1 & command2 Saya telah menonaktifkan perintah tunggu karena skrip diizinkan untuk melanjutkan ketika command2 selesai. Namun sepertinya perintah 1 sudah dimulai ketika saya menjalankan skrip. Bisakah saya memperbaikinya? Terima kasih
maero21
command1 dimulai langsung setelah command001 selesai. Anda dapat menggunakan set -xdi awal skrip untuk mencetak perintah yang dieksekusi.
michas
6

Saat meletakkan perintah ke latar belakang dari skrip, PID tidak ditampilkan di layar. Anda bisa menggunakan variabel builtin $!yang menyimpan PID dari proses terakhir sehingga Anda bisa menangkap PID dari command1.

command1 &
echo $!

akan mengulang PID dari command1.

Bash juga menyediakan perangkap bawaan yang dapat Anda gunakan untuk mendaftarkan urutan perintah yang harus dijalankan ketika sinyal tertentu diterima. Anda dapat menggunakan ini untuk menangkap SIGINT dan membunuh command1 sebelum keluar dari skrip utama mis

#!/bin/bash

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

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

Sekarang, ketika perintah 2 sedang berjalan, memukul Ctrl Cakan menyebabkan command1 dan command2 dikirim SIGINT.

Komunitas
sumber
Anda juga dapat menggunakan %nsintaks untuk mematikan pekerjaan latar belakang tertentu di shell ini. Biasanya Anda mengeluarkan kill %1untuk membunuh proses latar belakang terbaru dan satu-satunya. Dengan lebih banyak proses latar belakang, gunakan jobsuntuk melihat daftar terlebih dahulu.
9000
@ 9000: Ya tapi OP menjalankan perintah mereka dalam skrip (./execute.sh) jadi mendapatkan pekerjaan agar bekerja jauh lebih bermasalah tentunya?
@lain: tentu saja. Saya melewatkan poin tentang lari dari skrip.
9000
5

Versi GNU Paralel yang lebih baru akan melakukan apa yang Anda inginkan:

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

Atau jika commandtetap sama:

parallel command ::: 1 2
echo done

Tonton video intro untuk perkenalan cepat: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

Berjalan melalui tutorial (man parallel_tutorial). Anda perintah baris dengan mencintaimu karenanya.

Ole Tange
sumber
1

Ctrl+ Cmengirimkan sinyal SIGINT ke proses depan Anda, yaitu command2. command1dijalankan di latar belakang, oleh karena itu tidak peduli dengan aliran input.

Saat Anda mengetik command1 &, bash seharusnya memberi Anda proses 'PID, kira-kira seperti itu [1234]. Untuk mematikan proses ini, Anda dapat menggunakan kill 1234. Sekarang, jika Anda memiliki PID keduanya command1dan command2(lihat ps -ef), Anda dapat menggunakannya killuntuk mengakhiri semuanya:

kill pid1 pid2 pid3 ...

Trik kecil adalah menjalankan kedua perintah di latar belakang, dengan:

command1 & command2 &

Bash akan memberikan Anda kedua PID, siap untuk terbunuh. Trik lain adalah membawa kembali command1di latar depan setelah Anda membunuh command2:

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

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

Info lebih lanjut tersedia di sini: http://linuxg.net/how-to-manage-background-and-foreground-processes/

John WH Smith
sumber