シェルスクリプト入門2018年6月23日 | |
はじめに本文書ではシェルスクリプトの書き方を説明する。特に B シェル系のスクリプトについて説明する。 シェルとはシェルとは OS とユーザーの仲立ちをするもので、ここでは要するに UNIX 系システムで見られる端末のコマンドラインのことである。シェルにはいくつか種類があり、なにが使われているかは ps コマンドで調べることができる。 $ ps PID TTY TIME CMD 1937 pts/0 00:00:00 bash 2344 pts/0 00:00:00 ps 上記の例ではシェルに bash が使われていることがわかる。ここではシェルに bash が使われているという前提で話を進める。 シェルスクリプトとはシェルスクリプトというのは、シェルのコマンドを書き連ねたものである。コマンドの実行手順をまとめてひとつのコマンドとして扱うことができる。シェルスクリプトの書き方はシェルの種類によって異なることがある。 はじめてのシェルスクリプトecho コマンドを使うと文字列を出力できる。 $ echo test test このコマンドを使ってシェルスクリプトを作ってみる。次のような内容のファイルを用意する。 #!/bin/sh # test echo test このファイルの名前を "echo_test" としよう。これに実行権限を与える。 $ chmod +x echo_test 実行。 $ ./echo_test test "test" の文字列が出力される。 スクリプトの説明。 #!/bin/sh "#" 以降の文字列はコメント扱いされる。ただし、1 行目の "#!..." は特殊で、そこに書かれたコマンドによってスクリプトが実行される、という意味である。ここでは /bin/sh によりスクリプトが実行される。 # test これはほんとうのコメント。 echo test コマンドの実行。 コマンドを連ねて行くと、そのとおり実行される。 #!/bin/sh # test2 echo test1 echo test2 echo test3 これを "echo_test2" とする。 $ chmod +x echo_test2 $ ./echo_test2 test1 test2 test3 シェルの種類上記の "/bin/sh" の sh は B シェル (Bourne シェル) というもので、bash はその後継シェルである。これとは別系統で C シェル (csh/tcsh、tcsh は csh の後継) というものがあるが、スクリプトの書き方がかなり異なる。ここでの説明を B シェル系であると断っているのはそのためである。 ところで、bash を使っているのなら、先のスクリプトの 1 行目は "/bin/bash" でよいではないかと思うかもしれない。わざわざ sh を指定するのは、sh がすべての UNIX 系システムで必ず用意されているためである。ここでの説明で C シェル系ではなく B シェル系を選択しているのも同じ理由である。 変数つぎのように文字列に "=" で値を指定すると、変数を定義できる。 $ A=1 "=" の両側にスペースを入れてはいけない。 変数名の前に "$" をつけると、その変数の値を参照することができる。 $ echo $A 1 文字列に関連して変数を使う場合には注意が必要。 $ echo A = $A A = 1 $ echo "A = $A" A = 1 $ echo 'A = $A' A = $A 変数値の参照は "..." の中では値に展開されるが、'...' の中では展開されない。 環境変数変数には、そのシェルで定義され使用される変数と、環境変数がある。シェルスクリプトは、シェル上で別のシェルを起動して実行される。環境変数は、もとのシェルからスクリプト用のシェルに引き継がれる。 変数を環境変数にするには、export コマンドを使う。 $ export A たとえば、つぎのような var_test というスクリプトを作る。 #!/bin/sh echo "A = $A" echo "B = $B" つぎのように実行する。 $ chmod +x var_test $ A = 1 $ B = 2 $ export A $ ./var_test A = 1 B = 変数 A は環境変数なのでスクリプトから参照でき、値が表示されるが、B はそうではないので未定義の変数となり、値は表示されない。 変数の定義をコマンド実行と同時に行うと、値をスクリプトに渡すことができる。 $ B=2 ./var_test A = 1 B = 2 設定されている環境変数のリストは env コマンドにより得られる。 制御文if 文if 文により条件によって処理を分岐できる。 if [ 条件 1 ] then 条件 1 のときの処理 elif [ 条件 2 ] then 条件 2 のときの処理 else 上記条件以外のときの処理 fi つぎのような書き方をすることがある。 if [ 条件 1 ] ; then 条件 1 のときの処理 elif [ 条件 2 ] ; then 条件 2 のときの処理 else 上記条件以外のときの処理 fi セミコロン ";" は複数のコマンドを 1 行で書くための区切り文字である。 条件判定if 文で使われる条件判定にはつぎのようなものがある。 整数 int1 -eq int2 : int1 と int2 が等しいか int1 -ne int2 : int1 と int2 が等しくないか int1 -lt int2 : int1 が int2 より小さいか int1 -le int2 : int1 が int2 以下か int1 -gt int2 : int1 が int2 より大きいか int1 -ge int2 : int1 が int2 以上か 文字列 str1 = str2 : str1 と str2 が同じか str1 != str2 : str1 と str2 が同じでないか -z str : str が空か -n str : str が空でないか ファイル -f file : file が普通のファイルか -d file : file がディレクトリか -s file : file が空でないか -r file : file が読み込み可能か -w file : file が書き込み可能か -x file : file が実行可能か -L file : file がシンボリックリンクか その他 ! 条件 : 否定 条件1 -a 条件2 : AND 条件1 -o 条件2 : OR 実数の比較はそのままではできないので、特殊な書き方になる。 R=`echo "$A >= $B" | bc` if [ $R -eq 1 ] ; then ... fi ここで、`...` はその中の文字列をコマンドとして実行して、その結果を文字列として取り出すものである。bc に実数の比較式を渡して結果を得ている。1 だと真、0 だと偽である。 real1 == real2 : real1 と real2 が等しいか real1 != real2 : real1 と real2 が等しくないか real1 < real2 : real1 が real2 より小さいか real1 <= real2 : real1 が real2 以下か real1 > real2 : real1 が real2 より大きいか real1 >= real2 : real1 が real2 以上か for 文for 文で文字列のリストに対して処理を繰り返すことができる。 for 変数 in 文字列リスト do 処理 done 1 から 5 まで数字を表示するにはつぎのようにする。 for N in 1 2 3 4 5 ; do echo $N done break でループを抜けたり、continue でつぎのステップに進めたりできる。 for N in 1 2 3 4 5 ; do if [ $N = 2 ] ; then continue fi echo $N if [ $N = 3 ] ; then break fi done この例では 1 と 3 だけが表示される。 アスタリスク "*" でカレントディレクトリのファイルのリストを得ることができる。 for FILE in * ; do echo $FILE done つぎのようにすると、カレントにあるディレクトリに入ってそれぞれ同じ処理を行わせることができる。 for FILE in * ; do if [ -d $FILE ] ; then cd $FILE 処理 cd .. fi done while 文while 文ではある条件が成り立つあいだ処理を繰り返させることができる。 while [ 条件 ] do 処理 done 1 から 5 まで数字を表示するにはつぎのようにする。 I=1 while [ $I -le 5 ] ; do echo $I I=`expr $I + 1` done expr は整数の計算を行うコマンドである。 次のようにすると、ファイルから 1 行ずつとりだして処理することができる。 cat file | while read LINE ; do echo $LINE done case 文case 文では、文字列に対してパターンを並べ、合致したパターンの処理を実行させることができる。 case 文字列 in パターン 1) 処理 1 ;; パターン 2) 処理 2 ;; ... *) 上記パターンのどれにも合致しない場合の処理 ;; exac 環境変数 SHELL の値に応じて処理を変える場合は、つぎのように書ける。 case `basename $SHELL` in bash) bash 用の処理 ;; tcsh) tcsh 用の処理 ;; *) それ以外の処理 ;; esac basename は、パスの最後の文字列を取り出すコマンドである。"/bin/sh" ならば "sh" を返す。 パターンにはつぎのような特殊な書き方ができる。 * 文字列すべてに合致 ? 1 文字に合致 [...] この中に含まれるどれか 1 つの文字に合致 [!...] この中に含まれない文字に合致 また "[a-z]" で "a" から "z" までの文字、"[1-9]" で "1" から "9" までの文字、という書き方ができる。 "a" からはじまる文字列に対して処理するには、つぎのように書く。 case $STRING in a*) 処理 ;; ... exac 数値の計算シェルスクリプトでは直接数値の計算ができないので、数値の計算にはコマンドを使う。 整数の計算整数の計算には expr コマンドを使う。 expr int1 + int2 : 和 expr int1 - int2 : 差 expr int1 '*' int2 : 積 expr int1 / int2 : 商 expr int1 % int2 : 剰余 計算結果を得るには `...` を使う。 C=`expr $A '*' $B` 実数の計算実数の計算には bc コマンドを使う。式をパイプで渡す。 echo "scale=n; num1 + num2" | bc : 和 echo "scale=n; num1 - num2" | bc : 差 echo "scale=n; num1 * num2" | bc : 積 echo "scale=n; num1 / num2" | bc : 商 echo "scale=n; num1 % num2" | bc : 剰余 echo "scale=n; num1 ^ num2" | bc : 累乗 "scale=n" は小数点以下の出力桁数の指定で、n は任意である。 関数を使うこともできる。 $ echo "scale=3; sqrt(2)" | bc 1.414 入力コマンド read でユーザーの入力を得ることができる。たとえば、処理を進めてよいか確認するにはつぎのように書くことができる。 echo -n "OK? (y or n): " read R if [ $R != "y" ] ; then echo "abort." exit 0 fi これを実行すると、つぎのように入力待ちになる。 OK? (y or n): コマンドライン引数シェルスクリプト実行時に引数を指定することができる。指定した引数は変数 $1, $2, ... $9 に入る。 つぎのような arg_test というファイルを作る。 #!/bin/sh echo $1 $2 $3 つぎのように実行する。 $ chmod +x arg_test $ ./arg_test a b c a b c $1, $2, $3 がそれぞれ第 1、第 2、第 3 引数に対応しているのがわかる。 "$#" で引数の数を取得できるので、これでふつうのコマンドっぽい反応をさせることができる。 #!/bin/sh PROG=`basename $0` if [ $# -lt 1 ] ; then echo "usage: $PROG <arg>" exit 0 fi echo "arg = $1" これを arg_test2 として実行すると、つぎのようになる。 $ chmod +x arg_test2 $ ./arg_test2 usage: arg_test2 <arg> $ ./arg_test2 1 arg = 1 ここで $0 はコマンドラインで指定したスクリプトのパス (ここでは "./arg_test2" になる)、exit はスクリプトを終了させるコマンド (引数は終了コード) である。ちなみに、他のプログラムを呼び出した際の終了コードは $? で参照できる。 コマンドライン引数を処理するのに便利かもしれないコマンドとして、shift というものがある。これは、$2 の内容を $1 に、$3 の内容を $2 に、などと引数の内容をずらす。 while [ $# -gt 0 ] ; do echo $1 shift 1 done 上記のようにすると、それぞれの引数に対して $1 だけでアクセスできるため、処理を簡潔に書けるかもしれない。shift の引数はずらす個数である。 関数つぎのようにすると、関数を作ることができる。
func()
{
処理
}
これはコマンドのように使うことができる。 func arg1 arg2 ... 引数の扱いはコマンドライン引数と同じで、$1, $2, ... で扱う。たとえば、数値の計算をするための関数はつぎのように書ける。
calc()
{
echo "$1" | bc
}
A=`calc "2 * 3"`
echo $A
コマンド集echo文字列の表示。 echo string オプション -n で改行しないようにできる。 $ echo -n "aaa"; echo "bbb" aaabbb cat本来はファイルを結合するために使う。主にファイルの内容を出力するのに使われる。 cat file1 file2 > file3 複数の行にわたる文字列を表示する場合、echo で 1 行ずつ表示する代わりに、ヒア・ドキュメントというものが使える。
cat << END
calc()
{
echo "\$1" | bc
}
END
"END" は任意の文字列で、はじめに指定したこの文字列が出てくるまで表示が続く。変数は値に展開される。 grepテキストの中で指定した文字列がある行を表示する。 cat file | grep word オプション -v で逆に検索に引っかかった行を表示しない。たとえば、word1 がある行の中で word2 がある行は取り除きたい場合、つぎのようにする。 cat file | grep word1 | grep -v word2 cut文字列の一部を取り出すことがきる。 $ echo "abcdef" | cut -c2-4 bcd ある文字で区切られた文字列のあるフィールドを取り出すこともできる。 $ echo "ab,cd,ef" | cut -d',' -f2 cd sedテキストの編集ができる。 文字列の置換はつぎのようにする。 sed -e "s/string1/string2/g" file 検索語にスラッシュを含む場合は、区切り文字を他の文字で代用できる。 sed -e "s%string1%string2%g" file 上記のコマンドでは、編集結果が画面に出力される。オプション "-i" でファイルを上書きできる。 sed -i -e "s/string1/string2/g" file オプション "-e" の引数の中身は、編集範囲、コマンド、コマンドの引数となっている。たとえば、3 行目を削除したい場合は、次のようにする。 3 d 3 行目に文字列を挿入したい場合は、次のようにする。 3 i string 2 行目の後に文字列を挿入するには、次のようにする (3 行目に追加するのと同じ)。 2 a string string を含む行の後に文字列を挿入するには、次のようにする。 /string/ a string2 string1 から string2 までの範囲の文字列を削除したければ、次のようにする。 /string1/,/string2/ d 次のようにすると、string1 から string2 までの範囲の文字列を別の文字列に置き換えることができる。
/string1/,/string2/{
/string1/ i string
d
}
これは正確には、string1 を含む行の前に string を追加して、string1 から string2 までの範囲の文字列を削除している。 sortテキストの内容を並び替える。 cat file1 | sort > file2 単語帳を昇順に並べ替えたりできる。 cat << END | sort orange apple lemon END apple lemon orange オプション -r で降順にできる。 cat << END | sort -r orange apple lemon END orange lemon apple オプション -u で重複を 1 つにまとめることができる。 basename, dirnameパスのファイル名、ディレクトリ名を取り出す。 $ echo $SHELL /bin/bash $ basename $SHELL bash $ dirname $SHELL /bin basename でファイル名から拡張子を取り除くことができる。 $ basename file.txt .txt 参考文献
| |
| PENGUINITIS | |