lasciva blog

開発して得た知見やwebビジネスのストック

「入門UNIXシェルプログラミング」を読んだ

目的、モチベーション

今まではググりながら雰囲気でシェルスクリプトを書いていて、最近業務で使うことが増えてきて、シェル使いになりたいと思ったから。

全体の感想

一通りの文法がまとまっていたので、この1冊を理解すれば、ソースコードもガンガン読んでいけるレベルにはなると思う。
リダイレクトとかは特に雰囲気で使っていたレベルだったので、ちゃんと理解できてよかった。 たまに見る、 /dev/nullの意味もわかったので、これからはガンガン使おうと思う。

目次

概要

第1章 書き方にかかわる基本的な説明

1.4 ファイル名称の補完
ワイルドカード 説明
* 文字列全部
? 1文字
[...] の中に含まれている文字のどれか一つ
[!...] の中に含まれてない文字
1.5 引用符の使い方

シングルクォートの中で変数を展開したい場合

'Part1'"$VAR"'Part2'
1.9 コマンドのグルーピング
  • ()によるグルーピング: サブシェルで実行する。現在の環境を変えずに実行したい場合などに便利。
  • {}によるグルーピング: 現在のシェルで実行する。コマンドの結果をひとまとめにしたい場合などに便利。
1.10 制御文

testコマンドは []と同じ。

第2章 シェル変数

変数を明示的に使うには、{}で囲む。

$ FOO=abc
$ echo ${FOO}abc
2.5 位置パラメータ, 2.6 特殊な変数
変数 説明
$# 引数の数
$* 引数全体。ダブルクォートで括ると、一つの文字列として扱われる。
$@ 引数全体。ダブルクォートで括ると、それぞれが文字列として扱われる。
$? コマンド実行時の終了ステータス
$$ プロセスID
$! &でバックグラウンド実行させたときのプロセスID
$- 実行中のシェルのフラグの一覧

第3章 シェル関数、組み込みコマンド

3.1 シェル関数

3.1.4 関数をカレントシェルで利用すること
通常、シェルスクリプトに含まれるコマンドはそのシェルスクリプト内で動作し、起動したシェル上で動くわけではない。
カレントシェルで実行させるには .という組み込み関数を使用する。

$ . script_file
3.2 組み込みコマンド

3.2.1 ヌルコマンド(:)
何もしないが、いつも成功を返すコマンド。

# 無限ループ
while :
do
  if .....
  then
    break
  fi
done

# 空ファイルの作成
$ : > file

3.2.7 evalコマンド
複数の変換処理を一度に実行。

$ VAR1=val
$ VAR2=$"$VAR1"
$ echo $VAR2
$val
$ eval echo $"$VAR2"
val

3.2.10 exportコマンド
引数に指定した変数を、他のコマンドやシェルからも利用できるようにする。

3.2.12 readコマンド
キーボードからの入力を変数にセットする。

#!/bin/sh
echo -n "enter yes or no -->"
read ANSWER

3.2.13 readonlyコマンド
変数を書き換え不可にする。

3.2.19 typeコマンド
コマンドの取り扱いを表示。

$ type echo cd
echo is a shell builtin
echo is /bin/echo
cd is an alias for nocorrect cd
cd is a shell builtin
cd is /usr/bin/cd

3.2.20 umaskコマンド
ファイル生成時にどういうモードで作るかを決めれる。
ファイルの場合は666からumaskで指定した数字を指定したものができる。
デフォルト値は022なので、644のファイルができる。

$ umask
022
$ touch hoge
$ ls -l hoge
-rw-r--r--  1 user1  staff  0  2 10 10:34 hoge
$ umask 002
$ touch foo
$ ls -l foo
-rw-rw-r--  1 user1  staff  0  2 10 10:34 foo

3.2.21 unsetコマンド
変数や関数を消去する

3.2.22 waitコマンド
引数に渡したプロセスIDのプロセスが終了するまで待つ。

第4章 リダイレクションによるファイル操作

4.1 ファイルディスクリプタ
  • 0: 標準入力
  • 1: 標準出力
  • 2: 標準エラー
4.2 リダイレクト

リダイレクトとは、通常はキーボードからの入力を端末に出力するが、その入力元や出力先を変えること。

# 標準出力と標準エラーの両方をリダイレクト
$ cat abc def > nnn 2>&1
記法 説明
>file 標準出力をfileというファイルに書く
>file 標準出力をfileというファイルに追加書きする
>&m 標準出力をm番のファイルディスクリプタに書く
>&- 標準出力をクローズする
<file 標準入力をfileというファイルから読み込む
<&m 標準入力をm番のファイルディスクリプタから読み込む
<&- 標準入力をクローズする
<<word 標準入力をヒアドキュメントから読み込む
4.6 execコマンドとリダイレクション

execコマンドは、現在のシェルのプロセスをそのまま置き換えて新しいコマンドを実行させる。

# 標準出力を非表示に
exec > /dev/null

# 標準出力と標準エラーを非表示に
exec > /dev/null 2>&1 

# fileから入力する
exec < file

# n番目のファイルディスクリプタを使ってファイルをオープン
exec n> file
4.7 ファイルからの読み込み
# fileから一行ずつ読み込んで処理
while read LINE
do
   .....
done < file
4.10 ヒアドキュメント
# $VARは展開される
command << END
hoge is $VAR
END

# $VARは展開されない
command << \END
hoge is $VAR
END

# $VARは展開されない
command << 'END'
hoge is $VAR
END

# -をつけると行頭のtabが無視される
command <<- END
<tab>hoge is $VAR
END

# パイプにわたす
command << END | command
hoge is $VAR
END

第5章 環境

5.3 ユーザ情報、マシン情報

5.3.1 ユーザ名の取得
USERやLOGNAMEという環境変数でも取得できるが、書き換えられるので信用はできない。

$ whoami
hoge_foo
$ logname
hoge_foo
$ sudo su -
# whoami
root # 切り替わる
# logname
hoge_foo # もとのまま

スーパーユーザのみで実行させたい場合は、ユーザidで判断する。

if id | grep "^uid=0(" > /dev/null 2>&1
then
  echo "Is superuser"
else
  echo "Is not superuser"
fi
5.4 シグナルの処理

プロセスはシグナルを受け取ると実行を中止する。ハンドリングするためには trapコマンドを使う。

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

# シングルクォートで渡して、後ほど展開させる
trap 'rm -f /tmp/*.$$; exit 1' 1 2 3 15
数字 種類 説明
1 ハングアップ(SIGHUP)
2 割り込み(SIGINT) キーボードからの割り込みで中断させるためのキー。Ctrl-C
3 クイット(SIGQUIT)
9 キル(SIGKILL) プロセスを強制終了させる。trap等でも捕まえることはできない。
15 終了(SIGTERM) アプリケーションを終了させるときに用いられる。

第6章 コマンド行の解析、処理

6.2 コマンド行の書き方

引数が -でスタートするとオプションとして認識されてしまうため、 --を前につける。

$ mkdir -- -p
6.3 シェルスクリプトでのオプション処理

getoptsコマンドを使う

FLAG=FALSE
VALUE=
OPT=
while getopts fv: OPT
do
  case $OPT in
    f) FLAG=TRUE ;;
    v) VALUE=$OPTARG ;;
    \?) echo "Usage: $0 [-f] [-v value]" 1>&2
         exit 1 
         ;;
  esac
done
shift `expr $OPTIND - 1`

第7章 フィルタの使用法

7.2 sedコマンド
# 以下は同じ
cat file | sed -e 's/abc/ABC/'
sed -e 's/abc/ABC/' < file

# 慣習として使われてるだけで `/`のデリミータは任意の文字列でも大丈夫。
sed -e 's%abc%ABC%' file
7.3 sed を使っての編集
# 先頭に文字列追加
sed -e "s/^/top/"

# 末尾に文字列追加
sed -e "s/\$/top/"

# Pattern1とPattern2に囲まれてる部分の削除
sed -e "s/Pattern1*.Pattern2//"

# 大文字小文字の変換
cat file | tr '[a-z]' '[A-Z]' > upperfile

# タブをスペースに置換
sed -e "s/<tab>/<space>/"

# ホワイトスペースをスペースに置換
sed -e "s/[<tab><space>][<tab><space>]*/<space>/g"

# 空白行の削除
sed -e '/^[<tab><space>]*$/d'

# 行の指定
sed -e '5,$s/<tab>/<space>/g'

# 行の削除
sed -e '5,$d'

# 1行目からn行目まで表示
sed -n '1,np'

# BeginからEndの行を削除
sed -e '/Begin/,/End/d'

# ファイルを後ろから表示
grep -n '.*' | sort -n -r | sed 's/^[0-9]*://'

第8章 シェルのいろいろな機能

8.6 ファイルとディレクト
# ファイル名やディレクトリ名の単体での取得
basename `pwd`
# ディレクトリ名の取得
dirname `pwd`

# dir以下のファイルとディレクトリをすべて表示
find dir -print

# カレントディレクトリ以下のディレクトリのみすべて表示
find . -type d -print

# カレントディレクトリ以下のファイルのみすべて表示
find . -type f -print

# カレントディレクトリ以下の.swiftファイルのみすべて表示
find . -type f -name '*.swift' -print 

第11章 デバッグの手順、手法

11.2 デバッグオプション
  • -vオプション: 何を実行しようとしているのかが表示される
  • -xオプション: 実行している途中経過が出色される
$ cat shscript
#!/bin/sh
ABC=0
for i in 1 2 3
do
  ABC=`expr $ABC + $i`
done
echo $ABC

$ sh -v shscript
#!/bin/sh
ABC=0
for i in 1 2 3
do
  ABC=`expr $ABC + $i`
done
expr $ABC + $i
expr $ABC + $i
expr $ABC + $i
echo $ABC
6

$ sh -x shscript
+ ABC=0
+ for i in 1 2 3
++ expr 0 + 1
+ ABC=1
+ for i in 1 2 3
++ expr 1 + 2
+ ABC=3
+ for i in 1 2 3
++ expr 3 + 3
+ ABC=6
+ echo 6
6