UNIXシェルスクリプト第10章 Part9

コマンドをサーチするシェルスクリプト findcmd

IFS=:

for dir in `echo "$PATH"    |

               sed -e 's/^:/.:/'   \

               sed -e 's/::/:.:/g' \

               sed -e 's/:$/:./'`

$PATHを : で区切って、先頭や末尾にマークだけがある場合、あるいはカラの指定を全部カレントディレクトリになおしてdirに渡す。

UNIXシェルスクリプト第10章 Part8

ディレクトリをコピーするシェルスクリプト dircopy

find . -depth -print |

findコマンドは -depthオプションを使うとディレクトリ階層の深い順に表示させる。

付けた場合          付けなかった場合

a/b/c/d/e             a

a/b/c/d                a/b

a/b/c                   a/b/c/

a/b/f/d/e             a/b/c/d

a/b/f/d                a/b/c/d/e

a/b/f                   a/b/f

a/b                     a/b/f/d

a/x/f/d/e             a/b/f/d/e

a/x/f/d                a/x

a/x/f/o                a/x/f

a/x/f                   a/x/f/d

a/x/fo                 a/x/f/d/e

a/x                     a/x/f/o

a                        a/x/fo

-depthオプションをつける理由は、先に深い部分にアクセスして途中の読み込み不可や、検索不可といったエラーの要因を早めに見つけようとするため。

cpioを使ったコピーの場合、普通このオプションをつけた出力結果を渡す。

 

cpio -pdmu $TARGET 2>&1 |

cpioコマンドの基本オプションは3つある。

データを出力するときは-o、読み込んでくるときには-i、パス名を読み込んだコピーには-pを使う。

-dは必要に応じてディレクトリを作成する、-mはファイルの更新時刻を元のままのものを使う、-uは強制上書きという意味がある。

UNIXシェルスクリプト第10章 Part7

指定したフィールドの値を集計するシェルスクリプト addcolumn

awk '{total+=$'$COLUMN'} END {print total}'

awkコマンドは複数行のデータを処理する。

処理する内容をシングルクォートで囲まなくてはならないので、

$COLUMNはシングルクォートから外している。

END の後に記述した内容は複数行の処理を全部終わってから最後にやることを示す。

awkコマンドに渡すデータが : で句切られていたりする場合、

awk -F: という指定でフィールドセパレータを指示すればOK。

また、フィールド番号が負の数や0の場合はエラーを吐くのでチェックが必要。

UNIXシェルスクリプト第10章 Part6

行、単語、文字数をカウントするシェルスクリプト Wc

 wc $d/$PATTERN 2>/dev/null |

       grep -v " total$" >$TMP

wcコマンドはテキストファイルの単語数を表示する。

エラーが出ても、ここでは捨て去る。

最終行にtotalとしてその総計が出力されるが、この行も捨て去る。

 

set -- $LINE

-- はオプションがないという明示。

UNIXシェルスクリプト第10章 Part5

シェルアーカイブを作成するシェルスクリプト Shar

※シェルアーカイブというのはBSD4.4以降に作りこまれた機能の1つ。

少数のファイルをftpやmailで配布するのに便利なようにと作られたもの。

シェルスクリプトの中にファイルのリストと中身も入れて1つにしてしまうことで、

そのシェルスクリプトを実行すれば元のファイルを復元できるようにしている。

PCでいう自己展開形式のファイルを作成するようなもの。

 

使い方について

abcというディレクトリ下のファイルをシェルアーカイブにし、それを誰か別の人に渡したり別のディレクトリに移動させて展開するまで。

アーカイブを作成するには、

$ cd directory

$ Shar `find . -print` > directory.shar

このdirectory.sharファイルを人に渡したりメールで送ったりすればいい。

受け取った方は以下のようにすれば展開できる。

$ mkdir directory

$ mv directory.shar directory

 

$ cd directory

$ sh directory.shar

ただし、メールでそのまま渡された場合には$ sh directory.shar を行う前に。エディタを使ってこのファイルを開きメールのヘッダ部分を削除しておかなくてはならない。

なお、directory.sharという名称はどういう名前でも問題ない。

 

echo "#!/bin/sh"

echo "# This is a shell archive; to unpack:"

echo "# 1. Remove everything before the \"#!/bin/sh\"."

echo "# 2. Save the rest of the archive."

echo "# 3. Execute the archive by entering \"sh archive\"."

echo "#"

echo "# This archive contains the following files:"

echo "#"

作成するシェルアーカイブの先頭部分。

メッセージ中に日本語は書かないほうが良い。

 

for FILE

do

    echo "#    $FILE

done

このシェルアーカイブに含むファイルの名称をリストしている。

for FILE は for FILE in $* と同じ意味で、シェルスクリプトの引数全部が順番にこの変数に代入されていく。

 

sed 's/^X//'

sedコマンドで s/old/new とするとoldをnewで置き換える。

 

   sed 's/^X//' >$FILE <<\EOF

XThis is a

XSample file.

EOF

<<\EOF とリダイレクトすると、次にEOFという文字が現れるまでをコマンドの入力として扱える。

\ があれば変数を値に変換することができ、なければ変換は行われない。

このような書き方をヒア・ドキュメントという。

UNIXシェルスクリプト第10章 Part4

ディレクトリを作成するシェルスクリプト MkDir

IFS=/

for d in $1

IFS変数に / を代入することで区切り文字を / に変更できる。

$1を / で区切って分割し、変数dに入れてループさせる。

 

case $1 in

    /*)  DIR=    ;;

    *)   DIR=.  ;;

esac

相対パスなら先頭に ./ をつけて、絶対パスと同じ表記にしておく。

相対パス絶対パスについて

a/b/c/d/e という風に先頭に / が付かないのが相対パスでカレントディレクトリを基準とする。

/a/b/c/d/e というふうに先頭に / が付くのが絶対パス

UNIXシェルスクリプト第10章 Part3

プロセス名に対してシグナルを送るシェルスクリプト Kill

※killコマンドはプロセスIDに対してシグナルを送る。

プロセスIDは数字で表され、ユーザはpsコマンドを使って求めるプロセスが南蛮のプロセスIDで走っているのかを確認しなくてはならない。

 

プロセス番号ではなくプロセスの名前を指定してシグナルを送る。

実際にシグナルを送る前に確認応答が発生する。

 

-singnal

ここにはシグナルの番号やシグナルの種類を指定する。

kill(1)コマンドで指定できる形式でならどう書いても良い。

例えば -9 あるいは -KILL とすればそのプロセスに 9 番のシグナルを送る。

この指定がなかったらデフォルトとして 15 番を送る。

 

. SystemType.sh

ドットコマンド . で関数を定義したシェルスクリプトファイルを読みこませる必要がある。または、関数を直接書き込む必要がある。

 

ps $PS_OPTS

psコマンドはプロセスの情報を表示する。

 

sed '1d'

1行目を削除する。

 

grep "$NAME"

grepコマンドは指定した文字列を含む行を検索する。

 

grep -v "$0"

grepコマンドの -vオプションはパターンにマッチしなかった行を表示する。

 

exec < $PROCESS_LIST

while read LINE

do

    IFS=$OLD_IFS

    ....

done

execコマンドは新しいプロセスを生成せずにコマンドを実行する。

execコマンドを使って標準入力を直接ファイルから読み込むことで、while文の入力がこのシェルスクリプト上で動作する。

while read LINE

do

    IFS=$OLD_IFS

done < $PROCESS_LIST

とすると、このシェルスクリプトの子供のシェルとして動作する。

今回while文内でFOUNDという変数に値を代入し、while文を抜けてからその値によって処理を行っている。そのため、子供のシェルとして動作させてはいけない。

 

set $LINE

setコマンドはシェル変数を設定する。

setコマンドで位置パラメタをリセットすることにより、1番目のフィールドが$1、2番目のフィールドが$2というように順に代入される。

 

LINE=`echo "$LINE" | cut -c $COL-`

cutコマンドはファイルの各行から指定した範囲を表示する。

-cオプションは指定した部分を各文字を表示する。

$COL-のように指定すると、指定位置から行末までとなる。

 

set dummy $LINE

shift

PRONAME=$1

最初にdummyという文字列を意識的に入れておくことで、setコマンドにハイフンから始まる名前をオプションとして認識させないようにしている。

その後shiftで位置パラメタを1個ずらしてdummy部分を書く女子、コマンド名称をPRONAME変数に代入する。

 

"$PID $OWNER $PRONAME (y/n)? " </dev/tty

標準入力をPROCESS_LISTというファイルからリダイレクトしているために、このままでは標準入力を受け付けるところがない。

キーボードからの入力を可能にするには、このように/dev/ttyをリダイレクトしなくてはならない。