情報工学科 3年生対象 専門科目 システムプログラミング 第4回 シェルスクリプト 情報工学科 篠埜 功
シェルスクリプト シェルに対する命令をファイルに記述したもの シェルとは コマンドインタプリタ。UNIX系OSではシェルはユーザプログラムであり、自分でシェルを作成することもできる。
シェル(/bin/sh)に直接打ち込む例 [sasano@oli004 ~]$ sh sh-2.05b$ A=ls sh-2.05b$ $A <lsの実行結果> sh-2.05b$ シェルスクリプトは、シェル(通常は/bin/sh)に対する命令列をファイルに格納したものである。ここではファイルに入れずにシェル(/bin/sh)上で直接実行してみる。 (補足) shと打つことによって、shというファイルが環境変数PATHに入っているディレクトリから検索され、その結果/bin/shが見つかり、それが実行される。 A=ls などのように、変数名=文字列 の形で、変数を定義できる。=の前後にスペースを入れてはいけない。スペースを入れると、この場合、Aをコマンド名として解釈しようとしてcommand not foundになる。 変数の値の参照は、$変数名とすればよい。
(参考) /bin/tcshの場合 [sasano@oli004 4kai]$ set A=ls [sasano@oli004 4kai]$ $A <lsの実行結果が表示される> [sasano@oli004 4kai]$ /bin/tcsh では、上記のように、set A=lsの形で、setコマンドを用いてシェル変数を定義する。(ここでは=の前後にスペースがあってもよい。) シェル変数の一覧は $ set で画面に表示される。(shでもsetで一覧表示。)
環境変数 /bin/shや/bin/bashの場合: $ export シェル変数名 のようにすることにより、シェル変数が同一の変数名で環境変数となる。たとえば、 $ A=test $ export A など。環境変数の一覧は $ printenv で表示される。個々の環境変数の値は $ printenv A のように、環境変数名をprintenvコマンドの引数に与えると表示される。 /bin/tcshの場合: $ setenv A test のように、setenvコマンドを用いる。(=はないことに注意) 環境変数一覧、個々の値の表示については/bin/shと同じ。環境変数の値も$環境変数名で参照できるが、同じ名前のシェル変数がある場合、そちらが優先される。
環境変数の例 dateコマンド(日時の表示)を実行すると [sasano@oli004 4kai]$ date 2009年 10月 6日 火曜日 13:45:42 JST のようになるが、 [sasano@oli004 4kai]$ setenv LANG C のようにすると、 Tue Oct 6 13:47:27 JST 2009 のように英語表示になる。 (/bin/shの場合は、LANG=Cとしてからdateを実行すればよい)
シェル変数の例 PATH, HOME, USER, HOSTNAMEなどのシェル変数が通常使われている。 $ echo $PATH $ echo $HOME $ echo $USER $ echo $HOSTNAME などで確認できる。 /bin/shでも/bin/tcshでも同じ。
シェルスクリプト ファイルにシェルに対する命令(スクリプト)を書いたもの。 1行目に#!/bin/sh と書く。これによって、/bin/shがスクリプトを実行することになる。 #!/bin/bash, #!/bin/tcshなど、他のシェルを指定してもよいが、その場合はスクリプトの書き方は異なる。 ファイルの属性を、実行を許可するように変更する必要がある。 $ chmod 755 test.sh などのようにして変更できる。
例1(打ち込んで確認) (1)以下を中身とするtest1.shというファイルを作成 #!/bin/sh ls -l (2)ファイルの属性を変更 $ chmod 755 test1.sh (3)実行 $ ./test1.sh これによって、ls –lが実行される。あるいは、 $ /bin/sh test1.sh でもよい。 (4) カレントディレクトリのファイルリストが表示されることを確認。
シェル変数の使用(打ち込んで確認) (1)以下を中身とするtest2.shというファイルを作成 #!/bin/sh A=ls B=-l $A $B (2)ファイルの属性を変更 $ chmod 755 test2.sh (3) 実行 $ ./test2.sh (4) カレントディレクトリのファイルリストが表示されることを確認。(例1と同じ)
for文(例1)(打ち込んで確認) #!/bin/sh for i in 1 2 4 1 do 2 echo $i 4 done と表示されればOK。 echoは引数に与えられた文字列を表示するコマンド。$iが文字列に展開されてから表示される。
for文の構文、意味 構文 for variable in wordlists; do commands; done wordlistsの要素を左から順番に変数variableに代入し、commandsを実行する。 セミコロンは改行で置き換えてよい。 for文はコマンドであり、コマンドが書けるところには自由に書くことができる。例えばfor文の本体部分にfor文を書いてもよい。
for文の例2(打ち込んで確認) #!/bin/sh バッククオート`でコマンドを囲むと、その部分がコマンドの実行結果で置き換えられる。 for D in `date` do echo $D done バッククオート`でコマンドを囲むと、その部分がコマンドの実行結果で置き換えられる。 dateコマンドの出力結果にはスペースが含まれており、スペースで区切られた一つ一つがDに代入され、echoで1つずつ表示される。
for文の例3(打ち込んで確認) #!/bin/sh *はカレントディレクトリのファイルがスペースで区切られたものに展開される。 for L in * do echo $L done *はカレントディレクトリのファイルがスペースで区切られたものに展開される。 $ echo * で確認できる。 Lにはカレントディレクトリのファイル名が一つずつ代入され、それがechoで表示される。
for文の例4(打ち込んで確認) #!/bin/sh for F in * do cp $F $F.bak done Fにはカレントディレクトリのファイルのファイル名が一つずつ代入され、それがcpで.bakつきのファイルにコピーされる。
for文の例5(打ち込んで確認) #!/bin/sh for F in *.c do echo $F cp $F $F.bak done *.cは、カレントディレクトリにおいて、ファイル名の最後の部分が.cになっているファイルのファイル名がスペースで区切られたものに展開される。 Fにはカレントディレクトリの.cで終わるファイル名が一つずつ代入され、それがechoで表示されたのち、.bakつきのファイルにコピーされる。 第一回目に書いたシェルスクリプトは、上記のシェルスクリプトの最後にexit 0を加えたもの。
if文 構文 if commands; then commands; [elif commands; then commands;]… [else commands;] fi commands: コマンドをセミコロンで区切ったもの [ ] はオプション(なくてもよいという意味)。 意味 if の隣に書かれたcommands(の最後のコマンド)の終了statusが0ならthenパートを実行。そうでなければelif以下、あるいはelseパートを(もしあれば)実行。 セミコロンは改行で置き換えてよい。 if文はコマンドであり、コマンドが書けるところには自由に書くことができる。例えばif文のelseパートにif文を書いてもよい。
終了status コマンドは終了statusを返す。 シェルスクリプトではexit 0 等、exitの右に書く数によって終了statusを指定する。 Cのプログラムでは、main関数のreturn文あるいはexitシステムコールの引数によって終了statusを指定する。 コマンドの終了statusはシェルが受け取り、$?という変数に保持している。 (例) $ ls aaa $ echo $? もしaaaというファイルがなければlsコマンドの終了statusが1になっている。
if文の例1(打ち込んで確認) #!/bin/sh if test $1 -le $2 then echo $1 is less than or equal to $2. else echo $1 is greater than $2. fi testは比較などさまざまな判定を行うコマンド。オプションによりさまざまな判定が行える。 test arg1 –le arg2 は、arg1がarg2より小さいかどうか判定。 $1はシェルスクリプトの1番目の引数、 $2はシェルスクリプトの2番目の引数を表す。
if文の例2(打ち込んで確認) #!/bin/sh if diff $1 $2 > /dev/null then echo No differences were found between $1 and $2. else echo Some differences were found between $1 and $2. fi diffは2つのファイルの比較を行うコマンド。 終了statusは、同じとき0, 異なるとき1である。 diffコマンドの標準出力への出力は/dev/nullへリダイレクトされるので捨てられる。(リダイレクトについて後日解説する)
testコマンドについて testコマンドは大小比較などさまざまな判定に使われる。 数値比較、文字列比較、ファイル形式の判定、ファイルの修正時刻の比較などがある。さらに、条件をand, or, notで組み合わせることもできる。 testコマンドは非常によく使われるので略記法がある。 test …は [ … ] と略記してよい。 例えば、test $1 –le $2は、[ $1 –le $2 ]と書ける。 [の次の空白と、]の手前の空白は省けないので注意。
if文の例3(打ち込んで確認) #!/bin/sh if [ $1 -le $2 ] then echo $1 is less than or equal to $2. else echo $1 is greater than $2. fi 例1におけるtest $1 –le $2を[ $1 –le $2 ]で置き換えたもの。
ifコマンドについての補足1 ifコマンドはネストしてよい。例えば、elseパート有りのifコマンドをネストして、 if … then …
ifコマンドについての補足2 さきほどのifコマンドのネストは then … elif … else fi のように書いてもよい。この場合はifコマンドのネストではなく、1つのifコマンドである。