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

始めに

なんと第8章は約60ページもある。。。マラソンを走る前の気分です。。。まぁ、ぼちぼちやろうと思います。
肝心の内容ですが、文字列の扱いだったり、ファイルやディレクトリの扱いだったりと、UNIXらしい内容なので、文法や変数と違って楽しくできそうです。これで、やっと実際に使えそうなシェルスクリプトを書けそうです。

文字数の長さを調べる

exprコマンドを使う。exprコマンドは:(コロン)があると、右と左の文字列を比較して「先頭から何文字が等しいか」を返す。これを利用する。変数もこれで比較ができるが、変数に:や*が1文字だけ入っているとexprコマンドが演算子と判断するのでエラーになるので、別途対応する必要がある。

expr "hogehoge" : '.*'
8

終了コードにて文字列検索

$?には終了コードが格納されるので、ps -ax | grep hoge などのときに、hogeの文字列が見つかった場合は$?に0が格納され、見つからなかったときには1が格納される。サンプルを示す。

$ ps -ax | grep hoge
$ echo $?
1

exprを使った文字列の中の一部切り出し

exprコマンドは、:(コロン)の左の文字の中から右で指定された文字列の中で\(と\)の間の文字を切り出す。下記にサンプルを記載する。

$ expr "abcdefghijklmn" : "a.*\(e..h\)i.*"
efgh

exprとsedで最初の2文字を切り出す

sedの場合
STRING=`echo "$STRING" | sed -e 's/^..//'`
exprの場合
STRING=`expr "$STRING" : "..\(.*\)"`

setコマンドでの切り出し

setコマンドの引数を--とすると、その後の文字列を位置パラメータの1番目から順番に格納する。引数の数は変数$#に入る。これを利用して文字をIFSで切り出す事が可能。以下にサンプルを示す。

$ set -- `date`
$ while [ $# -gt 0 ]
> do
>       echo $1
>       shift
> done
Wed
Mar
24
21:42:52
JST
2010

cutコマンドでの切り出し

cutコマンドでも、区切り文字を指定して切り出すことが可能。下記の例では、区切り文字を「:」とし、2番目のフィールドを切り出すようにしている。

$ echo "abc:def:ghi" | cut -d':' -f2
def

echoで改行させない方法

echoコマンドで文字を出力した場合、echoコマンドは改行コードも出力するため表示結果も改行されてしまうが、-nオプションを使用することで改行させないことができる。ただし、これはBSD系だけで、System V系の場合はメッセージの最後に\cと言うコードをつける。このようなOSの種類によって使い方が異なる場合、チェックするシェルスクリプトを記載するか、シェル関数を使って判断させる。OSを判断するシェル関数は9章で。

$ echo -n "message ..... "
message ..... $

yesかnoかの入力の判定

スクリプトでYesかNoの判断するのは大変なので、シェル関数「GetYesNo」を使うことで判断できる。GetYesNo関数は第9章で。

画面のエコーバック

デフォルトでエコーバックされて、ユーザが何を入力したかわかるようになっている。エコーバックを無効にするには下記のコマンドを入力する。

$ stty -echo

この機能を使ってシェルスクリプトで入力されるパスワードを表示しないようにできる。

stty -echo
echo "Enter your password."
read PASSWORD
stty echo

basenameコマンド

引数で渡されたディレクトリやパスの最後の/以降のものを表示する。実際にそのファイルやディレクトリがあるかは確認しない。以下にサンプルを表示する。

$ basename /etc/hosts
hosts

dirnameコマンド

basenameコマンドと逆で、引数で渡されたパラメータの最後の/以降を切り落としたものを表示する。以下にサンプルを表示する。

$ dirname /etc/hoge/go/keiji/
/etc/hoge/go

findコマンド

findでファイルやディレクトリのリストを確認できる。findコマンドのパラメータを見ていく。

find . -print

カレントディレクトリ内のファイルやディレクトリのリストを表示する。

find `pwd` -print

カレントディレクトリ内のファイルやディレクトリのリストを完全パスで表示する。

find -type

typeオプションで表示するファイルの種類を絞ることができる。例えば、ディレクトリだけ表示させたいときは下記のようにtype d と指定する。

find . -type d -print
find -name

nameオプションは、指定された文字列とマッチするものだけを表示する。例えば、/usrの中にあるaで始まり.hで終わるファイルを表示させたい場合の例を示す。

$ find /usr -name "a*.h" print

また、!を使用することで否定する文字列を探すことも可能。以下にカレントディレクトリ内で拡張子がJPEGとtmp以外のファイルを表示するサンプルを示す。

$ find . -type f ! -name "*.jpeg" ! -name tmp -print

cpコマンドでのディレクトリのコピー

ファイルをコピーするにはcpコマンドでコピーする。もしディレクトリも丸ごとコピーしたければ-rオプションをつけてコピーする。

tarコマンドのでのディレクトリコピー

tarコマンドでディレクトリをコピーすると、コピー元のファイルやディレクトリの所有権やアクセス権や日付をそのまま残してコピーすることが可能。下記にtarコマンドでのコピーの例を示す。tarコマンドでファイル名に-を使うと、標準出力に書き出したり読み出したりすることができる。

(cd ソースディレクトリ; tar -cf - .) | (cd ディスティネーションディレクトリ; tar -xf -)

ファイルの日付による操作

lsコマンドでの日付比較

lsコマンドは-tオプションをつけると、ファイルの最終修正時刻の新しいもの順に並べる。さらにsedで先頭のファイルを抜き出せば、それが新しい方のファイルとなる。下記にサンプルを表示。

ls -t ファイル1 ファイル2 | sed -n '1p'
findコマンドでの日付比較

findコマンドの-newerオプションを使うと、最初の引数に指定されたファイルが新しければ、最初のファイルを表示し、2番目のファイルの方が新しい場合には何も表示しない。下記にサンプルを表示。

find ファイル1 -newer ファイル2 -print
ある時間より新しいファイルの検索

時間を指定してtouchコマンドでファイルを作成し、findコマンド等でそのファイルと比較させる。下記にtouchコマンドで2010年3月20日12時35分52秒のファイルを作成し、findコマンドで比較する例を表示。

$ touch -t 1003201235.52 test
$ find . -newer test -print

終わりに

この章に掲載されているコマンドやシェルスクリプトを1つ1つ試していくと、結構時間がかかりますが、この章では一般的なUNIXのコマンドの紹介も結構あったので、UNIXのコマンドを知っている方はさらっと読める章だと思います。あと、この章で紹介されているシェルスクリプトは、第2章あたりで紹介されていることも結構あるので、ちょうど良い復習になったりもしまする。

入門UNIXシェルプログラミング―シェルの基礎から学ぶUNIXの世界

入門UNIXシェルプログラミング―シェルの基礎から学ぶUNIXの世界

入門UNIXシェルプログラミング―シェルの基礎から学ぶUNIXの世界