シェルプログラミング入門5

#はじめに

この記事は
[シェルプログラミング入門1](https://qiita.com/twrcd1227/items/b7d6e16aa4e9f895a831)
[シェルプログラミング入門2](https://qiita.com/twrcd1227/items/03310278eea64319b0e4)
[シェルプログラミング入門3](https://qiita.com/twrcd1227/items/f89467925634cc0988b8)
[シェルプログラミング入門4](https://qiita.com/twrcd1227/items/617026321448b63d5f6b)
の続編である。

#環境

##マジックナンバー

マジックナンバーとは`#!`のこと

シェルスクリプトの先頭には以下のようになんのシェルを使うのか明示する。

```txt
#!/bin/sh       Bシェル
#!/bin/csh      Cシェル
#!/bin/ksh      Kシェル
```


またファイルの先頭が以下の文字でも判断できる

```txt
#  Cシェル上で実行するときCシェル
:  Bシェル
```

##環境変数

`set`コマンドを引数なしで実行すると現在セットされている変数の名前と値の一覧を表示できる。

`env`(もしくは`printenv`)コマンドでは現在セットされている環境変数の一覧を表示できる。`env | sort`とすると並べられる。

###子の環境の変更

環境変数を追加、変更するときは`export`を使う。

makeコマンドはCFLAGSという環境変数を見て処理する。

```sh
% CFLAGS=-g   #CFLAGSに-gを代入する
% export CFLAGS  #環境変数にCFLAGSを設定する
% make  
```

変数を一部だけに影響するようにする、つまりサブシェルだけで実行するには以下のの2通りの書き方がある。

```sh
(CFLAGS=-g; export CFLAGS; make)

CFLAGS=-g make
```

###親の環境の変更

基本的に親(プロセス)の環境は変更できない。

###PATH変数

以下のコマンドでPATH変数の一覧を表示する。

```sh
% echo $PATH
```


PATH変数のセットの仕方は以下の2通りある。

```sh
#上にあるほど優先
PATH=$PATH:/usr/local/bin
export PATH

#下にあるほど優先(推奨)
PATH="/usr/local/bin:$PATH"
export PATH

#ちなみに上と下なら下の方が優先度が高い
```

#ユーザー情報

ユーザーの名前を調べるには以下のようにする

```sh
% whoami
user
% logname
user
% id
uid=501(user) gid=20(staff) ・・・・
% who  #システムを利用しているユーザのリストの表示
user   console  May 11 13:15 
user   ttys000  May 11 18:45 
% who
% who am i
user   ttys000  May 11 18:45 
```

`su`を使うとユーザを変えられる。

```sh
% whoami
user
% su another  #anotherというユーザに切り替える
Password:
% whoami
another
% logname   #lognameの結果は変化しない
user
```

#マシン情報

`hostname`(なければ`uname`)コマンドを使う。

```sh
% hostname
host
```

#シグナルの処理

##シグナルとは

シグナルは`kill`コマンドで送信される。

```sh
% sleep 1200 &  #バックグラウンドで1200秒何もしない
[1] 2540
% ps | grep sleep  #sleepのプロセスを表示
 2540 ttys000    0:00.00 sleep 1200
 2544 ttys000    0:00.00 grep sleep
% kill -1 2540  #1番のシグナルを送る
[1]  + hangup     sleep 1200     
```

sleepコマンドはハングアップシグナルを受け取った。

シグナルはオンラインドキュメントで調べられる。
重要なシグナルを以下にあげる。

###0番

シグナル0は実際のシグナルではない。
exitコマンドで終了したり、シェルスクリプトの終わりに達したりしたとき、シェルは自分自身にシグナル0を送る。

###1番

ハングアップシグナル。(**SIGUP**)
制御端末の切断、仮想端末の終了

###2番

割り込みシグナル(**SIGINT**)。普通はキーボードからの割り込み。
`Ctrl-C`や`Delete`と同じ。実行中の処理を中断させる。

###3番

クィットシグナル(**SIGQUIT**)。キーボードからのクィット信号に割り当てられる。`Ctrl-\`と同じ。

###9番

キルシグナル(**SIGKILL**)。プロセスを強制終了する。
このシグナルはキャッチできない。

###15番

終了シグナル(**SIGTERM**)。アプリケーションを終了させる。シグナル番号なしの`kill`コマンドと同じ。

##`trap`コマンド


###trapコマンドとは

trapコマンドを使うとシグナルを受け取ったときの処理を設定できる。

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

シェルプログラムは上から下に実行されるので、trapコマンドはできるだけシェルスクリプトの始めの方に書く。

###シグナルのキャッチ

trapコマンドは多くがシェルスクリプト内で使われて、シグナルを受け取ったときにできるだけ後処理をやってから終了したときに使われる。
そういった時は1,2,3,15を捕まえる。

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

tmpの





*******************************



###シグナルの無視

''と空にするとその後に示したシグナルを受け取っても無視する。

```sh
trap '' 1 2 3 15
```

###シグナルのリセット

trapのcommand部に何も書かなかったら、シグナルを受け取ったときに無視するのではなく、シグナル本来の意味のまま動作する。

```sh
trap 1 2 3 15
```

###trapを使った例

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

シェルスクリプトの一番最後に引数0でこの関数を呼ぶ。正常終了でも異常終了でも一時ファイルを消去してから終わる。また、正常終了の時0、異常終了の時は1をセットする。

```sh
trap '' 2 3
   ・・・・
trap ':' 2
cat file
trap '' 2
   ・・・・
```

シグナル2,3を無視することでキーボードからの割り込みをなくし、catコマンドでファイルを画面に表示する直前にシグナル2番の割り込みを受け付ける。

#終わりに

前回までのリンク

[シェルプログラミング入門1](https://qiita.com/twrcd1227/items/b7d6e16aa4e9f895a831)
[シェルプログラミング入門2](https://qiita.com/twrcd1227/items/03310278eea64319b0e4)
[シェルプログラミング入門3](https://qiita.com/twrcd1227/items/f89467925634cc0988b8)
[シェルプログラミング入門4](https://qiita.com/twrcd1227/items/617026321448b63d5f6b)