Cara Menggunakan Sinyal Linux di Skrip Bash

Diterbitkan: 2022-08-09
Laptop Linux menampilkan prompt bash
fatmawati achmad zaenuri/Shutterstock.com

Kernel Linux mengirimkan sinyal ke proses tentang peristiwa yang mereka butuhkan untuk bereaksi. Skrip yang berperilaku baik menangani sinyal dengan elegan dan kuat dan dapat membersihkan di belakangnya sendiri bahkan jika Anda menekan Ctrl+C. Begini caranya.

Sinyal dan Proses

Sinyal adalah pesan singkat, cepat, satu arah yang dikirim ke proses seperti skrip, program, dan daemon. Mereka membiarkan proses tahu tentang sesuatu yang telah terjadi. Pengguna mungkin telah menekan Ctrl+C, atau aplikasi mungkin mencoba menulis ke memori yang tidak dapat diaksesnya.

Jika pembuat proses telah mengantisipasi bahwa sinyal tertentu mungkin dikirim ke sana, mereka dapat menulis rutin ke dalam program atau skrip untuk menangani sinyal itu. Rutinitas seperti itu disebut penangan sinyal . Ini menangkap atau menjebak sinyal, dan melakukan beberapa tindakan sebagai tanggapannya.

Cara Mengelola Proses dari Terminal Linux: 10 Perintah yang Harus Anda Ketahui
TERKAIT Cara Mengelola Proses dari Terminal Linux: 10 Perintah yang Harus Anda Ketahui

Linux menggunakan banyak sinyal, seperti yang akan kita lihat, tetapi dari sudut pandang skrip, hanya ada sebagian kecil sinyal yang mungkin menarik bagi Anda. Khususnya, dalam skrip non-sepele, sinyal yang memberi tahu skrip untuk dimatikan harus dijebak (jika memungkinkan) dan pematian yang anggun dilakukan.

Misalnya, skrip yang membuat file sementara atau membuka port firewall dapat diberi kesempatan untuk menghapus file sementara atau menutup port sebelum dimatikan. Jika skrip mati begitu menerima sinyal, komputer Anda dapat dibiarkan dalam keadaan yang tidak terduga.

Inilah cara Anda dapat menangani sinyal dalam skrip Anda sendiri.

Memenuhi Sinyal

Beberapa perintah Linux memiliki nama yang samar. Tidak begitu perintah yang menjebak sinyal. Itu disebut trap . Kita juga dapat menggunakan trap dengan opsi -l (list) untuk menunjukkan kepada kita seluruh daftar sinyal yang digunakan Linux.

 perangkap -l 

Daftar sinyal di Ubuntu dengan trap -l

Meskipun daftar bernomor kami berakhir pada 64, sebenarnya ada 62 sinyal. Sinyal 32 dan 33 hilang. Mereka tidak diimplementasikan di Linux. Mereka telah digantikan oleh fungsionalitas di kompiler gcc untuk menangani utas waktu nyata. Semuanya mulai dari sinyal 34, SIGRTMIN , hingga sinyal 64, SIGRTMAX , adalah sinyal waktu nyata.

Anda akan melihat daftar yang berbeda pada sistem operasi mirip Unix yang berbeda. Di OpenIndiana misalnya, sinyal 32 dan 33 hadir, bersama dengan sekelompok sinyal tambahan yang membuat jumlah total menjadi 73.

Daftar sinyal di OpenIndiana dengan trap -l

Sinyal dapat direferensikan dengan nama, nomor, atau dengan nama singkatnya. Nama singkat mereka hanyalah nama mereka dengan "SIG" terkemuka dihapus.

Sinyal dinaikkan karena berbagai alasan. Jika Anda dapat menguraikannya, tujuan mereka terkandung dalam nama mereka. Dampak sinyal termasuk dalam salah satu dari beberapa kategori:

  • Terminate: Proses dihentikan.
  • Abaikan: Sinyal tidak mempengaruhi proses. Ini adalah sinyal informasi saja.
  • Core: File dump-core dibuat. Hal ini biasanya dilakukan karena proses telah melanggar dalam beberapa cara, seperti pelanggaran memori.
  • Berhenti: Proses dihentikan. Artinya, itu dijeda , bukan dihentikan.
  • Continue: Memberi tahu proses yang dihentikan untuk melanjutkan eksekusi.

Ini adalah sinyal yang paling sering Anda temui.

  • SIGHUP : Sinyal 1. Sambungan ke host jarak jauh—seperti server SSH—telah tiba-tiba terputus atau pengguna telah keluar. Skrip yang menerima sinyal ini mungkin berhenti dengan baik, atau mungkin memilih untuk mencoba menyambung kembali ke host jarak jauh.
  • SIGINT : Sinyal 2. Pengguna telah menekan kombinasi Ctrl+C untuk memaksa proses menutup, atau perintah kill telah digunakan dengan sinyal 2. Secara teknis, ini adalah sinyal interupsi, bukan sinyal penghentian, tetapi skrip yang terputus tanpa penangan sinyal biasanya akan berhenti.
  • SIGQUIT : Sinyal 3. Pengguna telah menekan kombinasi Ctrl+D untuk memaksa proses berhenti, atau perintah kill telah digunakan dengan sinyal 3.
  • SIGFPE : Sinyal 8. Proses mencoba melakukan operasi matematika ilegal (tidak mungkin), seperti pembagian dengan nol.
  • SIGKILL : Sinyal 9. Ini adalah sinyal yang setara dengan guillotine. Anda tidak dapat menangkap atau mengabaikannya, dan itu terjadi secara instan. Proses segera dihentikan.
  • SIGTERM : Signal 15. Ini adalah versi SIGKILL yang lebih perhatian. SIGTERM juga memberi tahu proses untuk dihentikan, tetapi dapat terjebak dan proses dapat menjalankan proses pembersihannya sebelum ditutup. Ini memungkinkan shutdown yang anggun. Ini adalah sinyal default yang dimunculkan oleh perintah kill .

Sinyal di Baris Perintah

Salah satu cara untuk menjebak sinyal adalah dengan menggunakan trap dengan nomor atau nama sinyal, dan respon yang diinginkan terjadi jika sinyal diterima. Kita dapat mendemonstrasikan ini di jendela terminal.

Perintah ini menjebak sinyal SIGINT . Responsnya adalah mencetak sebaris teks ke jendela terminal. Kami menggunakan opsi -e (enable escapes) dengan echo sehingga kami dapat menggunakan penentu format “ \n ”.

 trap 'echo -e "\nCtrl+c Terdeteksi."' TANDA 

Menjebak Ctrl+C pada baris perintah

Baris teks kita dicetak setiap kali kita menekan kombinasi Ctrl+C.

Untuk melihat apakah jebakan dipasang pada sinyal, gunakan opsi -p (perangkap cetak).

 perangkap -p TANDA 

Memeriksa apakah jebakan dipasang pada sinyal

Menggunakan trap tanpa opsi melakukan hal yang sama.

Untuk mengatur ulang sinyal ke keadaan normal yang tidak dijebak, gunakan tanda hubung “ - ” dan nama sinyal yang terperangkap.

 perangkap - TANDA
 perangkap -p TANDA 

Menghapus jebakan dari sinyal

Tidak ada keluaran dari perintah trap -p menunjukkan tidak ada perangkap yang dipasang pada sinyal tersebut.

Menjebak Sinyal dalam Skrip

Kita dapat menggunakan perintah trap format umum yang sama di dalam skrip. Skrip ini menjebak tiga sinyal berbeda, SIGINT , SIGQUIT , dan SIGTERM .

 #!/bin/bash

jebakan "echo I was SIGINT dihentikan; keluar" SIGINT
jebakan "gema saya dihentikan SIGQUIT; keluar" SIGQUIT
jebakan "gema saya dihentikan SIGTERM; keluar" SIGTERM

gema $$
penghitung = 0

sementara benar
melakukan 
  echo "Nomor lingkaran:" $((++penghitung))
  tidur 1
selesai

Tiga pernyataan trap ada di bagian atas skrip. Perhatikan bahwa kami telah menyertakan perintah exit di dalam respons untuk setiap sinyal. Ini berarti skrip bereaksi terhadap sinyal dan kemudian keluar.

Salin teks ke editor Anda dan simpan dalam file bernama “simple-loop.sh”, dan buat agar dapat dieksekusi menggunakan perintah chmod . Anda harus melakukannya untuk semua skrip dalam artikel ini jika Anda ingin mengikutinya di komputer Anda sendiri. Cukup gunakan nama skrip yang sesuai dalam setiap kasus.

 chmod +x simple-loop.sh 

Membuat skrip dapat dieksekusi dengan chmod

Sisa skrip sangat sederhana. Kami perlu mengetahui ID proses skrip, jadi kami memiliki skrip yang menggemakannya kepada kami. Variabel $$ menyimpan ID proses skrip.

Kami membuat variabel yang disebut counter dan mengaturnya ke nol.

Perulangan while akan berjalan selamanya kecuali dihentikan secara paksa. Ini menambah variabel counter , menggemakannya ke layar, dan tidur sebentar.

Mari jalankan skrip dan kirim sinyal berbeda ke sana.

 ./simple-loop.sh 

Skrip yang mengidentifikasinya telah dihentikan dengan Ctrl+C

Ketika kami menekan "Ctrl + C" pesan kami dicetak ke jendela terminal dan skrip dihentikan.

Mari kita jalankan lagi dan kirim sinyal SIGQUIT menggunakan perintah kill . Kita harus melakukannya dari jendela terminal lain. Anda harus menggunakan ID proses yang dilaporkan oleh skrip Anda sendiri.

 ./simple-loop.sh
 bunuh -SIGQUIT 4575 

Skrip yang mengidentifikasinya telah dihentikan dengan SIGQUIT

Seperti yang diharapkan, skrip melaporkan sinyal yang tiba kemudian berakhir. Dan akhirnya, untuk membuktikan maksudnya, kita akan melakukannya lagi dengan sinyal SIGTERM .

 ./simple-loop.sh
 bunuh -SIGTERM 4584 

Skrip yang mengidentifikasinya telah dihentikan dengan SIGTERM

Kami telah memverifikasi bahwa kami dapat menjebak banyak sinyal dalam skrip, dan bereaksi terhadap masing-masing sinyal secara independen. Langkah yang mempromosikan semua ini dari menarik menjadi bermanfaat adalah menambahkan penangan sinyal.

Menangani Sinyal dalam Script

Kami dapat mengganti string respons dengan nama fungsi dalam skrip Anda. Perintah trap kemudian memanggil fungsi tersebut ketika sinyal terdeteksi.

Salin teks ini ke editor dan simpan sebagai file bernama “grace.sh”, dan buat itu dapat dieksekusi dengan chmod .

 #!/bin/bash

trap graceful_shutdown SIGINT SIGQUIT SIGTERM

anggun_shutdown()
{
  echo -e "\nMenghapus file sementara:" $temp_file
  rm -rf "$temp_file"
  KELUAR
}

temp_file=$(mktemp -p /tmp tmp.XXXXXXXXXX)
echo "File temp telah dibuat:" $temp_file

penghitung = 0

sementara benar
melakukan 
  echo "Nomor lingkaran:" $((++penghitung))
  tidur 1
selesai

Skrip menetapkan jebakan untuk tiga sinyal berbeda— SIGHUP , SIGINT , dan SIGTERM —menggunakan pernyataan trap tunggal. Responsnya adalah nama fungsi graceful_shutdown() . Fungsi dipanggil setiap kali salah satu dari tiga sinyal yang terperangkap diterima.

Script membuat file sementara di direktori “/tmp”, menggunakan mktemp . Template nama file adalah “tmp.XXXXXXXXXX”, jadi nama filenya adalah “tmp.” diikuti oleh sepuluh karakter alfanumerik acak. Nama file bergema di layar.

Sisa skrip sama dengan yang sebelumnya, dengan variabel counter dan loop while tak terbatas.

 ./grace.sh 

Sebuah skrip melakukan shutdown yang anggun dengan menghapus file sementara

Saat file dikirimi sinyal yang menyebabkannya ditutup, fungsi graceful_shutdown() dipanggil. Ini menghapus file sementara tunggal kami. Dalam situasi dunia nyata, itu bisa melakukan pembersihan apa pun yang diperlukan skrip Anda.

Selain itu, kami menggabungkan semua sinyal yang terperangkap bersama-sama dan menanganinya dengan satu fungsi. Anda dapat menjebak sinyal satu per satu dan mengirimkannya ke fungsi pengendali khusus mereka sendiri.

Salin teks ini dan simpan dalam file bernama "triple.sh", dan buat itu dapat dieksekusi menggunakan perintah chmod .

 #!/bin/bash

perangkap sigint_handler SIGINT
perangkap sigusr1_handler SIGUSR1
perangkap exit_handler EXIT

fungsi tanda_penangan() {
  ((++sign_count))

  echo -e "\nSIGINT menerima $sigint_count waktu."

  if [[ "$sigint_count" -eq 3 ]]; kemudian
    echo "Memulai close-down."
    loop_flag=1
  fi
}

fungsi sigusr1_handler() {
  echo "SIGUSR1 dikirim dan diterima $((++sigusr1_count)) waktu."
}

fungsi exit_handler() { 
  echo "Penangan keluar: Skrip ditutup..."
}

gema $$
sigusr1_count=0
tanda_hitung=0
loop_flag=0

while [[ $loop_flag -eq 0 ]]; melakukan
  bunuh -SIGUSR1 $$
  tidur 1
selesai

Kami mendefinisikan tiga jebakan di bagian atas skrip.

  • Satu menjebak SIGINT dan memiliki penangan yang disebut sigint_handler() .
  • Yang kedua menjebak sinyal yang disebut SIGUSR1 dan menggunakan penangan yang disebut sigusr1_handler() .
  • Perangkap nomor tiga menjebak sinyal EXIT . Sinyal ini dimunculkan oleh skrip itu sendiri saat ditutup. Menyetel pengendali sinyal untuk EXIT berarti Anda dapat mengatur fungsi yang akan selalu dipanggil saat skrip dihentikan (kecuali jika dimatikan dengan sinyal SIGKILL ). Handler kami disebut exit_handler() .

SIGUSR1 dan SIGUSR2 adalah sinyal yang disediakan sehingga Anda dapat mengirim sinyal khusus ke skrip Anda. Bagaimana Anda menafsirkan dan bereaksi terhadap mereka sepenuhnya terserah Anda.

Mengesampingkan penangan sinyal untuk saat ini, isi skrip seharusnya sudah tidak asing lagi bagi Anda. Ini menggemakan ID proses ke jendela terminal dan membuat beberapa variabel. Variabel sigusr1_count mencatat berapa kali SIGUSR1 ditangani, dan sigint_count mencatat berapa kali SIGINT ditangani. Variabel loop_flag disetel ke nol.

Perulangan while bukanlah perulangan tak berhingga. Ini akan berhenti mengulang jika variabel loop_flag disetel ke nilai bukan nol. Setiap putaran while loop menggunakan kill untuk mengirim sinyal SIGUSR1 ke skrip ini, dengan mengirimkannya ke ID proses skrip. Script dapat mengirim sinyal ke diri mereka sendiri!

Fungsi sigusr1_handler() menambah variabel sigusr1_count dan mengirim pesan ke jendela terminal.

Setiap kali sinyal SIGINT diterima, fungsi siguint_handler() menambah variabel sigint_count dan menggemakan nilainya ke jendela terminal.

Jika variabel sigint_count sama dengan tiga, variabel loop_flag disetel ke satu dan sebuah pesan dikirim ke jendela terminal yang memberi tahu pengguna bahwa proses shutdown telah dimulai.

Karena loop_flag tidak lagi sama dengan nol, loop while berakhir dan skrip selesai. Tapi tindakan itu secara otomatis memunculkan sinyal EXIT dan fungsi exit_handler() dipanggil.

 ./triple.sh 

Sebuah skrip yang menggunakan SIGUSR1, membutuhkan tiga kombinasi Ctrl+C untuk menutup, dan menangkap sinyal EXIT saat dimatikan

Setelah tiga kali menekan Ctrl+C, skrip akan berhenti dan secara otomatis memanggil fungsi exit_handler() .

Baca Sinyalnya

Dengan menjebak sinyal dan menanganinya dalam fungsi handler langsung, Anda dapat membuat skrip Bash Anda rapi di belakang mereka sendiri bahkan jika tiba-tiba dihentikan. Itu memberi Anda sistem file yang lebih bersih. Ini juga mencegah ketidakstabilan saat Anda menjalankan skrip berikutnya, dan—tergantung pada tujuan skrip Anda—bahkan dapat mencegah lubang keamanan.

TERKAIT: Cara Mengaudit Keamanan Sistem Linux Anda dengan Lynis