「シェルスクリプトの基礎 - シグナルとtrapコマンド」の版間の差分

📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

ページの作成:「== 概要 == シグナルとは、プロセス間で通信を行うための仕組みであり、Linuxカーネルに実装されている。<br> 実行中のプロセス…」
 
文字列「__FORCETOC__」を「{{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板 |description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This pag…
 
(同じ利用者による、間の2版が非表示)
104行目: 104行目:
== trap コマンド ==
== trap コマンド ==
==== trapコマンドの使用方法 ====
==== trapコマンドの使用方法 ====
trapコマンドは、送出されたシグナルを捕捉して、予め指定された処理を実行するコマンドである。<br>
<code>trap</code>コマンドは、送出されたシグナルを捕捉して、予め指定された処理を実行するコマンドである。<br>
  trap "<コマンド>" <シグナルリスト>
  trap "<コマンド>" <シグナルリスト>
<br>
<br>
実行中のシェルスクリプトに対して送出されたシグナルは、trapコマンドを使用することで捕捉することができる。
実行中のシェルスクリプトに対して送出されたシグナルは、<code>trap</code>コマンドを使用することで捕捉することができる。<br>
 
<br>
killコマンド等により、シグナルリストに指定されたシグナルが送出されると、trapコマンドはそれを捕捉して、指定したコマンドを実行する。
<code>kill</code>コマンド等により、シグナルリストに指定されたシグナルが送出されると、<code>trap</code>コマンドはそれを捕捉して、指定したコマンドを実行する。<br>
trapコマンドを使用することにより、各シグナルの規定の動作を置き換えることができる。
<code>trap</code>コマンドを使用することにより、各シグナルの規定の動作を置き換えることができる。<br>
ただし、強制終了のシグナルである9番はtrapすることはできないため、注意すること。
<br>
 
<u>ただし、強制終了のシグナルである9番はtrapすることはできないため、注意すること。</u><br>
  trap "echo trapped." 2
  trap "echo trapped." 2
   
   
120行目: 120行目:
<br>
<br>
==== trap処理のリセット ====
==== trap処理のリセット ====
trap コマンドでシグナル捕捉時に実行するように指定した動作は、リセットを行うことで解除することができる。
<code>trap</code>コマンドでシグナル捕捉時に実行するように指定した動作は、リセットを行うことで解除することができる。<br>
 
<code>trap</code>コマンドにシグナルリストのみを指定して、指定されたシグナルの捕捉処理をリセットする。<br>
trap シグナルリスト
trap <シグナルリスト>
→ trap コマンドにシグナルリストのみを指定し、指定されたシグナルの捕捉処理をリセットする。
<br>
 
<code>trap</code>コマンドで指定した処理をリセットする場合(例: <code>trap "rm -f *.tmp; exit 1" 1 2 3 15</code>)、<br>
trap コマンドで指定した処理をリセットしたい場合、つまり trap 'rm -f *.tmp; exit 1' 1 2 3 15 などと指定していた動作を、各シグナルのデフォルトの動作に戻したい場合は、trap 1 2 3 15 のように trap コマンドにリセットしたいシグナルのみを指定し実行する。
各シグナルの標準の動作に戻すには、<code>trap 1 2 3 15</code>のように、リセットするシグナルのみを指定して実行する。<br>
 
<br>
trap コマンドの処理を指定していた部分に何も書かないことにより、シグナル受信時にデフォルトの動作をするようになる。ただし、処理部分に何も書かないと言っても**「trap '’ 1 2 3 15」とはまったく意味が違う**ので注意が必要だ。
<code>trap</code>コマンドの処理を指定した部分に何も記述しないことにより、シグナル受信時に標準の動作に戻すことができる。<br>
<br>
<u>※注意</u><br>
<u>ただし、<code>trap "" 1 2 3 15</code>と記述した時、シグナルを捕捉した場合は""を実行する。</u><br>
<u>これは何も処理をしないという意味になり、結果として、該当するシグナルを無視するという設定になってしまう。</u><br>
<br>
trap 'echo trapped.' 2
# ここで、[Ctrl]+[C]キーを押下する
trapped.  # trapコマンドに指定した処理が実行される
trap 2  # trapコマンドの設定をリセットする
# ここで、[Ctrl]+[C]キーを押下する
# 指定した処理が解除されているのが確認できる
<br><br>


== trapコマンドの応用例 1 ==
trapコマンドをシェルスクリプトに組み込むことで、<br>
シグナル受信により実行途中で終了する場合に行う終了処理を指定することができる。<br>
trap 'command' 1 2 3 15  # 通常の用途であれば、trapするシグナルは1, 2 , 3, 15のみでよい
<br>
シェルスクリプト内で受け取る可能性があるシグナルには9番(<code>SIGKILL</code>)もあるが、<u>9番(<code>SIGKILL</code>)は指定してもtrapすることができない。</u><br>
したがって、シェルスクリプト内でtrap処理を行う場合は、1、2、3、15のみを指定する。<br>
<br>
以下の例では、<code>trap</code>コマンドを使用して、終了前にゴミ掃除を実行している。<br>
<br>
実行中のシェルスクリプトを割り込み等により途中で終了した場合、スクリプト中で作成した一時ファイルが残ってしまうことがある。<br>
このような一時ファイルを残さないようにするため、<code>trap</code>コマンドを使用して、終了前にゴミ掃除を実行する。<br>
<syntaxhighlight lang="sh">
#!/usr/bin/env sh
# ゴミ掃除用のtrap処理を指定する
trap 'echo "trapped."; rm -f temp.$$; exit 1' 1 2 3 15
# trap時に削除するファイルを作成する。
echo "Trap Test." > temp.$$
echo "作成されたファイルを確認する"
ls -l temp.$$
# [Ctrl]+[C]キーを押下するまでループ
echo "[Ctrl]+[C]キーを押下してください"
while :
do
    :
done
# 出力
作成されたファイルを確認する
-rw-r--r-- 1 sunone sunone 11  6月 2日 14:01 temp.9535
[Ctrl]+[C]キーを押下してください
# ここで、[Ctrl]+[C]キーを押下する
trapped.  # トラップ処理が実行されて、一時ファイルが削除される
</syntaxhighlight>
<br><br>


== trapコマンドの応用例 2 ==
<code>EXIT</code>シグナルをtrapして、シェルスクリプト終了時に必ず実行される処理を指定する。<br>
trap 'command' EXIT  # シェルスクリプト終了時に送信される0番のシグナル(EXIT)をtrapする
<br>
シェルスクリプトが終了する時に終了メッセージを表示するような処理は、予め、<code>EXIT</code>シグナルをtrapすることで実現できる。<br>
また、<code>trap '<コマンド>' 0</code>のように0番を指定しても結果は同じになるが、<br>
trap処理が終了処理であることが明示的に分かる<code>EXIT</code>を指定する方がよい。<br>
<br>
以下の例では、<code>EXIT</code>シグナルをtrapして終了処理を実行している。<br>
このテクニックは、<code>exit</code>コマンドを実行する分岐が複数存在して、かつ、終了時に共通の処理を行う必要がある場合において非常に有効である。<br>
<syntaxhighlight lang="sh">
#!/usr/bin/env sh
# EXITシグナルをtrapして終了メッセージを指定する
trap "echo '`basename $0`を終了します'" EXIT
# 他のシグナルもtrapしておく
trap "echo '他のシグナルをtrapしました'" 1 2 3 15
echo "[Ctrl]+[C]キーを押下してください"
# [Ctrl]+[C]キーで終了するため、sleepする
sleep 10
exit 0
# 出力
[Ctrl]+[C]キーを押下してください
# ここで、[Ctrl]+[C]キーを押下する
   
   
trap '' 1 2 3 15 と書くと、シグナルを捕捉した場合は '' を実行する、つまり何もしない処理を実行するという意味になり、結果として該当するシグナルを無視するという設定になってしまう。
他のシグナルをtrapしました
xxx.shを終了します  # INTシグナルで終了した場合でも、EXITシグナルはtrapできる
</syntaxhighlight>
<br><br>


$ trap 'echo trapped.' 2
{{#seo:
※ ここで Ctrl+c を押す。
|title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki
$ trapped.
|keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板
#↑trap に指定した処理が実行されている。
|description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux
 
|image=/resources/assets/MochiuLogo_Single_Blue.png
$ trap 2
}}
#↑trap をリセットする。
※ ここで Ctrl+c を押す。
$
#↑指定した処理が解除されているのが確認できる。
<br><br>


__FORCETOC__
__FORCETOC__
[[カテゴリ:シェルスクリプト]]
[[カテゴリ:シェルスクリプト]]