Tech Blog

環境変数、シグナルについて

2021-02-27

シェルスクリプトの定義

シェルスクリプトの頭の#!はマジックナンバーと呼ばれ、 これを書くことによってこのファイルがインタプリタ的に動作するものとして認識されます。

シェルはコマンドを実行するときにexecシステムコールでコマンドを実行しようとします。 そのファイルの先頭に#!があれば、そのコマンドがインタプリタ型(1行毎に処理していく) と判断します。

#!の後に、どのシェルを使うか指定します。

#!/bin/shと指定すると、Bシェルが使われます。

環境変数

「環境変数」とは、プロセスが作られたときに引き継がれる「名前とその値」が組になったものです。

プロセスができるときに親(そのプロセスを作ったもの)の環境変数をコピーしてきます。

環境変数はシェルスクリプト実行時にも親の環境変数をコピーします。

そのため、環境変数はシェルスクリプトで使えるようになります。

あくまでコピーして利用するものであり、そのプロセスで値を変更しても親の値には影響しません。

setコマンドを引数なしに実行すると、今そこでセットされている変数の名前と値の一覧を確認できます。

envコマンドでは今セットされている環境変数の一覧が得られます。

環境変数を変更・追加する

環境変数を変更・追加する場合は、exportコマンドを使います。

export <環境変数名>

PATH変数

PATH変数にはディレクトリの一覧が入っており、何かコマンドを打ったとき、 このディレクトリを順番にそのコマンドがあるかないかを調べていきます。

コマンドをPATH変数に追加すると普通のコマンドとして使えるようになります。

以下のようにセットします。

export PATH="/usr/local/opt/bison/bin:$PATH"

ユーザー情報・マシン情報

ユーザーの名前を確認する方法としてwhoamilognameidwhoといったコマンドがあります。

whoami

whoamiは現在のログインユーザーを表示します。

logname

lognameは、suでユーザーを変えても、元のログイン時のユーザーを表示します。

idコマンドは、ユーザー名とユーザーID、グループ名とグループIDを表示します。

whoコマンドはそのシステムを使用しているユーザーのリストを出します。

以下は、idコマンドを使ってそのユーザーIDが0かどうかを判定するシェルスクリプトです。

#!/bin/sh
if id | grep "^uid=0(" > /dev/null 2>&1
then
	echo "Is superuser"
else
	echo "Is not superuser"
fi

ホスト名の取得

hostnameコマンドでそのマシンの名称を取得できます。

uname -nでも取得可能です。

シグナルの処理

普通、プロセスはシグナルを受け取ると実行を中断します。

trapコマンドによりシグナルを受け取った際の挙動を変更できます。

trapのコマンド内でexitしなければ、そのシェルスクリプトはシグナルを受け取ったときに 処理していたところから再開されます。

trap command-list signal_number # シグナルを受け取って処理する
trap '' signal_number # シグナルを無視する
trap signal_number # シグナルをリセットする

killコマンドでシグナルを送る

sleepコマンドで1200秒間何も何もしないプロセスを作成し、kill -1コマンドでプロセスを ハングアップします。

sleep 1200 &
[1] 3987
ps | grep sleep
 3987 ttys000    0:00.00 sleep 1200
kill -1 3987
[1]  + 3987 hangup     sleep 1200

シグナルの種類

0

シグナル0は実際のシグナルではありません。

exitコマンドで終了したり、シェルスクリプトの終わりに達した場合、シェルは自分自身にこのシグナル0を 送ります。

trapに0番を指定すると、そのシェル自身の終了処理を行わせることができます。

1

ハングアップシグナル(SIGHUP)です。 端末を切断したりするために使います。

2

割り込みシグナル(SIGINT)です。

キーボードからの割り込み信号を意味します。(Ctrl + CやDelete)

3

クィットシグナル(SIGQUIT)です。 (Ctrl + \)を打つことで生成します。

9

キルシグナル(SIGKILL)です。

プロセスを強制終了します。trapの引数にこの番号を指定しても、処理ができずに強制終了します。

15

終了シグナル(SIGTERM)です。

アプリケーションを終了する際に使用するシグナルで、killコマンドで発行するデフォルト のシグナルです。

シグナルのキャッチ

trap 'rm -f /tmp/*.$$; exit 1' 1 2 3 15

killコマンドや割り込みが発生した場合は、 /tmp/下に作成したファイルを削除する後処理を書いている例です。

実行させるコマンドをシングルクォートで囲んでいるのは展開させずにコマンドに渡すためです。

シグナルの無視

空のコマンドを指定すると、シグナルを受け取っても無視します。シグナルを受け取っていない ように振る舞います。

trap '' 1 2 3 15

シグナルのリセット

trap   1 2 3 5

シグナルを受け取ったときに、そのシグナル本来の意味のままに動作します。

trapを使った例

一時ファイルの削除

#!/bin/sh
Cleanup(){
	rm /tmp/*.$$
	exit $1
}
trap 'Cleanup 1' 1 2 3 15
 
Cleanup 0

上の例では、割り込みが発生しても一時ファイルを消去してから終了します。

また、終了コードを0、1で動的に出し分けます。

割り込みキーの一時解除

trap '' 2 3
.....
.....
trap ':' 2
cat file
trap '' 2 3
.....
.....

catコマンド実行時のみ割り込みを許可する例です。

無限ループを抜けるためにキーボードの割り込みを使う

STOP=
trap 'STOP=1; trap 2 3' 2 3
while :
do
  ......
  if [ $STOP ]; then
    break
  fi
done