トップへ
田村研究室

インターネット利用技術演習

2009年度

2009
6/1

シェルスクリプト

シェルスクリプトとは

シェルスクリプトは、Unixのシェルで利用できるコマンドを連続して実行するために並べて記述したものである(スクリプト言語とは).つまり,実行したいコマンドを並べて書き込んだテキストファイルを用意しておくと,UNIXのシェルがそれを解釈して,記述内容に沿って一連のコマンドを自動連続実行することができるようになっている.このファイルのことをスクリプトファイルと呼ぶ.

シェルスクリプトの基本構造

スクリプトファイルの内容は,次のようなものである.

#!/bin/sh

コマンド1
コマンド2
コマンド3
...

#コメント行

シェルスクリプトでは、1行目に必ず「#!このスクリプトを解釈して実行してくれるプログラム(スクリプト言語の実行環境)の具体的なファイル名」を書く。この例では、Unix基本シェルの本体である「/bin/sh」を絶対パスで指定している(絶対バスに関してはUnixファイルシステムを参考のこと).

シェルスクリプトでは、行頭に「#」があるとコメント行として扱われるが、この一行目のように「#!」と、すぐ続いて「!」が書かれていると実行環境の指定と解釈される。

シェルは、csh系とsh系に大きく分けられる(参考:コマンドラインシェル)。スクリプトを書く際、両者で書き方が大きく異なる。しかし、シェルスクリプトの記述にはsh系を用いた方がよい。(参考: 有害なcshプログラミング)

ここでは、/bin/shを用いたスクリプト作成について説明する。

シェルスクリプトファイルの実行の仕方

このような内容のテキストファイルを用意した後,次のコマンドでそのテキストファイルに実行属性を付与する.

% chmod a+x 今作成したスクリプトファイルの名前

実行属性に関しては,再度Unixファイルシステムの最後の方を参照すること.簡単に説明すれば,作成したスクリプトファイルを「実行」することができるようにするための設定である.

実行属性が付与されたスクリプトファイルであれば次のように先頭に「./」をつけた上,ファイル名をタイプするだけでそのファイルを実際に実行することができる.

% ./スクリプトファイルの名前

先頭の「./」は,カレントディレクトリの指定を意味し,「現在開いているディレクトリの中に」存在するスクリプトファイルの実行をシェルに指示するために必要である.

シェルスクリプトの記述方法(基本テクニック)

以下に,シェルスクリプトで使用する基本的な操作といくつかのテクニックを紹介する.使用するコマンドはほとんどUNIXシェルで説明されている基本的なコマンドばかりである.

シェルの標準出力

標準出力(通常は画面)にメッセージを表示するにはechoコマンドを使用する.

 echo なにかメッセージ

ただし,表示したいメッセージ中に,もしもUNIXシェルに対して特別な意味を持つ記号が含まれていた場合,このままで出力できない.例えば,「>」記号などが含まれていた場合,そのままではリダイレクション機能と間違えられてしまうため,表示できない.このような場合のために,メッセージはダブルクォーテーション「" "」で囲っておけばよい.

 echo ">などを含むメッセージ"

ファイルの中身を標準出力に表示するには,catコマンドを使用する.

 cat ファイル名

変数

シェルスクリプトでは,プログラミング言語のように,「変数」を利用することができる.変数には,処理の途中結果などを格納しておくことができる.例えば,入力/出力先のファイル名を格納しておくためなどによく利用される.

変数への値の登録

シェルスクリプトでの場合,通常のプログラミング言語のような変数宣言は必要なく,次のようにいきなり初期値を代入することで使用可能になる。ただし、「=」の前後にスペースを入れてはいけない点に注意が必要。ここで指定できる値は数値だけでなく,文字列でもよい.

 hoge=なにか値

文字列を指定する場合,先ほどのメッセージ出力と同様,設定したい文字列に特殊な意味を持つ記号を含めたいことがある.その際には,次のようにダブルクォーテーションで囲えばよい.

 hoge="なにか値"

変数から値を取り出す

格納した変数の値を,後で参照するときには変数名の頭に$をつける。例えばechoコマンドで内容を標準出力へ出力するには、次のように利用すればよい.

  echo $hoge

もしも,$hogeの内容を出力するのではなく,「$hoge」という文字をそのまま表示させたい場合には,ダブルクォーテーションで囲ってもダメで,シングルクォーテーションで囲わなければならない.

  echo '$hoge'

別コマンドの出力内容を変数に登録

別のコマンドの出力を、変数に格納するにはバッククォートを用いる.ただのシングルクオートとは異なるので注意.通常のシングルクォート「'」では動作しない.

バッククォートの入力は,日本語キーボードでは通常「@」キーをSHIFTキーと同時に押すことで入力できる.

 hoge=`コマンド`

変数内容の加工

変数の中身が文字列の場合,次のように文字列の一部だけを取り出すこともできる.

  ${hoge#パターン} ←文字列の先頭から最短一致した「パターン」を削除
  ${hoge##パターン}←文字列の先頭から最長一致した「パターン」を削除
  ${hoge%パターン} ←文字列の末尾から最短一致した「パターン」を削除
  ${hoge%%パターン}←文字列の末尾から最長一致した「パターン」を削除

例えば$hogeに,「sampletxt.txt」が格納されていた場合,次を実行すると

 echo ${hoge%txt*}
 echo ${hoge%%txt*}

その結果は

 sampletxt.
 sample

となる.この場合,パターンとして「txt*」が指定されておるが,末尾の「*」 は,メタキャラクタである.このため,上の例ではもっ とも短くあたはまったもの,下の行ではもっとも長くあてはまったものが削除されている.

環境変数

自分で設定した変数ではなく,最初からシステム側からシェルに引き渡されてきた変数も存在する.このような変数を環境変数と呼ぶ.

環境変数の一覧は,次のコマンドで調べることができる.

set

特定の環境変数だけを表示するには,次のように普通の変数と同様に表示することができる.

 echo $user

自分で用意した変数を,環境変数として登録することもできる.その場合には,次のように,exportコマンドを利用する.

 hoge="なにか値"
 export hoge

あるいは,次のようにする.途中にある「;」は,コマンドの区切りを意味し,続いて2番目のコマンドを記述するための記法である.このように一行で書いておくと,対応がとりやすいため,よく用いられる.

 hoge="なにか値"; export hoge

通常の変数は,シェルスクリプトの実行が終了した時点で消滅してしまうが,一度環境変数として登録すると,引き続いてシステムに存在する.このため続けて別のシェルスクリプトを実行した場合,その別のシェルスクリプトからも利用することができるようになる.

ファイルの操作

あるコマンドの実行結果を,ファイルへ保存するには,シェルのリダイレクション機能を利用すればよい.

  コマンド > ファイル名

ファイル名で指定したファイルがすでに存在する場合には,上書きしてしまう.そうではなく,既存ファイルの末尾へ次々と追記するためには次のようにすればよい.

  コマンド >> ファイル名

出力ではなく,逆にファイルからデータを読み込みたい場合には,次のように記述すれば,変数hogeに,ファイルに書かれた内容を取り込むことができる.

 hoge=`cat ファイル名`

数の計算(expr)

変数には数値データも格納できる.この場合,それを用いて計算することもできる.例えば,次のコマンドで足し算の結果を表示することができる.

 expr 3 + 4

+演算子の両側にはスペースが必須である点に注意すること.これにより7という答えが表示される.両方数字で演算するだけではなく,片方や両方とも変数を用いた計算をすることもできる.例えばhogeという名前の変数を使った計算は次のようにかける.

 expr $hoge + 1

また,計算結果を新たに変数に格納し直すには,次のようにする

 hoge=`expr $hoge + 1`

条件分岐(if)

通常のプログラミング言語と同様に,条件次第で実行内容を変更することができる.次のようにifコマンドと「[」(test)コマンドを利用する.

 if [ 条件 ] ; then
    条件が成立したときだけ処理する内容をこの間に書いておく    
 fi

または,

 if [ 条件 ] ; then
   条件が成立したときに処理する内容
 else
   条件が成立しなかった時の内容をこっちに
 fi

複数の条件を書くこともできる.「elif」の部分は何個でも連結することができる

 if [ 条件 ] ; then
   条件が成立したときの内容
 elif [ 別の条件 ] ; then
   (前の条件が成立せずに)別の条件が成立したときの内容
 fi

条件の書き方(test)

条件の書き方は次のように「[」コマンドを利用する.

 [

実はこの「[」コマンドは「test」コマンドの別名である.

 test

これらを用いて例えば次のように条件を書く

 [ -f ファイル名 ]

この条件の最初に書いてあるものは,それに続くファイル名で指定されたファイルが,実際に存在するかどうかという条件を示している.同様に,次のような条件を書くことができる.

  • -f : その名前の通常ファイルが存在するかどうか
  • -d : その名前のディレクトリが存在するかどうか
  • -x : その名前のファイルに実行属性があるかどうか
  • -w : その名前のファイルに書き込み属性があるかどうか
  • -r : その名前のファイルに読み込み属性があるかどうか
  • -z : その名前のファイルのサイズが0かどうか
  • -e : その名前のファイルかディレクトリが存在するかどうか

例えば,ファイル「count.dat」が存在すれば,そのファイルを読み込むようにするには,次のようにすればよい.

 if [ -e count.dat ] ; then
  $hoge=`cat count.dat`
 fi

また,数値データを格納してある変数に対しては,次のような条件を書くことができる.

 [ $hoge -eq 5 ]
  • -eq : 等しいかどうか(equal)
  • -ne : 等しくないかどうか(not equal)
  • -gt : よりも大きいかどうか(greater than)
  • -lt : よりも小さいかどうか(litller than)
  • -ge : 同じか大きいかどうか(greater or equal)
  • -le : 同じか小さいかどうか(litller or equal)

文字列を格納してある変数に対しては,次の比較演算を行うことができる.

 [ $hoge = "文字列" ]
  • = : 文字列が等しいかどうか
  • < : 文字列がアルファベット(文字コード)順で,小さいかどうか
  • > : 文字列がアルファベット(文字コード)順で,大きいかどうか
  • != : 文字列が等しくないかどうか

数値に対する大小比較と間違えやすいので,注意すること.

繰り返し文(for,while)

次のfor文で,繰り返し処理を記述できる.

  for 変数 in 要素1 要素2 要素3 .... ; do

     (変数を使って繰り返し処理する部分)

  done

例えば,「data.001」「data.002」「data.003」という三つのファイルに対して同じような処理を繰り返したい場合には,次のように書く.これは単に三つのファイルの中身を表示するだけである.

  for i in data.001 data.002 data.003; do
    cat $i
  done

要素を並べて記述する代わりに,次のようにメタキャラクタを使用することもできる.

  for 変数 in * ; do

     (変数を使って繰り返し処理する部分)

  done

このほかにwhile文もある.通常はfor文で事足りるが,while文はread文と組み合わせて,あるファイルから一行づつ内容を読み込んで処理するような処理を記述するときに便利である.

  while read 変数 ; do
   
    (変数を使って繰り返し処理する部分)

  done < ファイル名

正規表現

シェルで説明したメタキャラクタは,正規表現で使用される.正規表現とは,文字列のパターンを表記するためのものである.

文字列の置き換え(sed)

文字列を目的に応じて書き換えて使用するためのコマンドにsedコマンドがある.簡単な使い方は次のとおりである.

sed 's/文字列1/文字列2/' ファイル名 

これで,「ファイル名」で指定されたファイル内に存在する文字列のうち,文字列1で指定されたものが文字列2に書き換えられて,標準出力(画面)に表示される.もしもこの結果を別のファイルに格納したければ,つぎのようにリダイレクション機能を用いればよい.

sed 's/文字列1/文字列2/' ファイル名 > 出力ファイル名

また,スクリプト中で,変数に格納されている文字列を操作したい場合には,次のようにechoコマンドと組み合わせればよい.「|」はパイプと呼ばれ,一つめのコマンドの出力結果を,次のコマンドの入力とするためのものである.

echo 変数 | sed 's/文字列1/文字列2/'

sedでは、文字列1の場所に「.」を含んでいると、任意のどんな一文字にもマッチする。また「*」は任意の繰り返しを意味するため、「.*」はど んな文字列にもマッチする。また「^」は行頭、「$」は行末にマッチする。これらの特殊文字は「\.」や「\?」のように「\」を付記することでその特殊 文字そのものを表現することが可能である。

文字列2の場所に「&」を含んでいると、文字列1としてマッチした内容に置換される。

例1:

echo "abcdef" | sed 's/abc.../&ABCDEF/'

例1の結果

abcdefABCDEF

例2:

echo "http://server?no1=abc&no2=def" | sed 's/.*\?//'

例2の結果

no1=abc&no2=def

文字列の探索(grep)

grepコマンドは,たくさんのファイルの中から,指定した文字列を探し出すコマンドである.

 grep "探したい文字列" ファイル名1 ファイル名2 ....

例えば,カレントディレクトリの中の全ファイルから,「body」という文字を探すには,次のように使用する.

  grep "body" *

ファイルの探索(find)

ディレクトリの中にあるファイルも含めて,ファイル名の検索をするコマンドである.ワイルドカードも使用できる.例えば,今いる場所から先頭がabcのファイル名をすべて探し出すには次のコマンドを使用する

 find . -name "abc*"

最初の.は,現在のディレクトリを示す.

xargs

xargsは標準入力からファイル名の一覧を受け取って,指定されたコマンドに引きわたして実行するコマンドである.特にfindコマンドとペアで利用すると非常に便利なコマンドである.

find . -name "*.txt" | xargs grep "abc" 

この例を実行すると,現在のディレクトリ(サブディレクトリを含む)に存在するすべてのtxtファイルをfindコマンドによって検索す る.findコマンドだけだとそのままファイル名の一覧だけが表示されて終わりだが,xargsコマンドをパイプ処理によってつなげているため,そのファ イル名の一覧がxargsに引きわたされ,xargsがgrepコマンドを呼出してやる.これにより,現在のディレクトリに含まれる全txtファイルに対 して"abc"という文字列を捜し出すgrep処理を実行できる.

別のスクリプト言語

シェルスクリプトの目的は,自動的なコマンド処理の記述である.しかし,ある程度複雑な自動処理を記述しようとすると,だんだんシェルスクリプトで は記述が困難になってくる.それは,シェルスクリプトが本来大規模なプログラミングを想定していないものであるため,大きなスクリプトになると,プログラ ム的な見通しが悪くなってしまうため(プログラムの最初から最後まで読みとおしにくくなり,部分部分に分けて作ることも難しい)である.このため,別のス クリプト言語が利用されることも多い.

●awk●

awkは,sedと組み合わせてある程度まとまった量のスクリプトを記述するためのスクリプト言語である.sedは基本的に文字列の置換を行うことが主目的であるが,awkは特定の文字列を見付けて,その場所で変数操作やメッセージ出力などが記述できる.

●perl●

perlは,システム管理やCGIで多用されるスクリプト言語である.シェルスクリプトだけでは書くことが面倒な,あるていどまとまった量のスクリ プトを書くときに使用する.上記のsedとawkの組合せでも可能であるが,より簡単に記述できたり,よりシステム管理に強力な記述が書けるため広く利用 されている.