shell script
- はじめに
- シェルスクリプトの書式
- 制御演算子
- ヒアドキュメント
- ループ
- 例
- シンプルなループ例
- 無限ループ
- 条件分岐
- if
- case
- 変数と演算子
- memo
- 参考文献・参考ウェブページ
- 履歴
このページはシェルスクリプトについて記載しています。
shell script はbash やcsh などのshell で使用できるスクリプト。
作業の自動化などに効率が良い。
- 文字列処理はシェルスクリプトの優れた利点。
他の言語では非常に面倒になってしまう。
何かの区切り文字をつかって各フィールドを区切ることはきわめて重要。
タブ、カンマ、コロン などの実際のデータ中で使用されない文字を使えば十分。
また、再利用性を高めるために、元のデータの持っていたデータの構造をできるだけ残すべき。
最近はXML によるデータの一般化が進んでいるので非常に有効である。
- ファイルの先頭文字を#! とすると先頭行の残りの文字列を
インタプリタへのパス名とみなす。
オプションはひとつだけ指定が可能。標準は/bin/sh で以下のようになる。
#! /bin/sh
- 終了ステータス
慣習的に0 は成功を表す。
シェルスクリプトではC言語などとは違い、0 以外はすべて失敗を表す。
- 未定義の定義
「未定義」は拡張機能の実現と標準への準拠を両立させるため、とある。
-
-
-
-
制御演算子の例
./configure && make && make install
これはconfigure がEXIT_SUCCESS したらmake を行い、
make がEXIT_SUCCESS したら make install を行う。
[ -f ${filename} ] || exit 1
など、以上終了したら終了とかける。
また、|| を使用するとEXIT_FAILURE シグナルを取得・判断できる。
ヒアドキュメントを使うとecho をたくさん使わなくてもすむ。
ここではEND をヒアドキュメントのラベルに使用しているが、
END でなくても、終了のラベルとあわせれば何でもよい。
cat <<END
COMMENT
1. COMMENT_1
2. COMMENT_2
3. COMMENT_3
END
ヒアドキュメントの指定に<<の代わりに <<- を使うと、
行頭のインデントを無視してくれる。
ディレクトリ内部のファイルに対して操作を行うスクリプト。
書式は
for PARAM_NAME in WORD_1 WORD_2 .
do
COMMAND
COMMAND
.
done
使用例1
カレントディレクトリのtar.gz ファイルをすべて解凍する。
for i in ./*.tar.gz; do
tar xzvf "$i" || continue
done
使用例2
for i in /etc/rc$runlevel.d/K* ; do
check_runlevel "$i" || continue
# Check if the subsystem is already up.
subsys=${i#/etc/rc$runlevel.d/K??}
[ -f /var/lock/subsys/$subsys -o -f /var/lock/subsys/$subsys.init ] \
|| continue
# Bring the subsystem down.
if egrep -q "(killproc |action )" $i ; then
$i stop
else
action $"Stopping $subsys: " $i stop
fi
done
中央大学シェルスクリプト説明ウェブページ[シェルの置換機能]
ディレクトリ内部のすべてのzip ファイルを展開する。
$ for i in *.zip; do unzip $i; done
#!/bin/sh
while /bin/true # 無限ループ
do
echo ""
date
ps -ef | grep apache2
sleep 1 # 延々と実行しないように休みを入れる
done
- 分岐命令
通常
if cmd1
then
cmd1_follows_cmd
elif cmd2
then
cmd2_follows_cmd
else
cmd_when_all_failed
fi
否定条件
if ! cmd1
then
cmd1_follows_cmd
else
cmd_when_all_failed
fi
条件の合成
and
if cmd1 && cmd2
then
cmd1_follows_cmd
else
cmd_when_all_failed
fi
or
if cmd1 || cmd2
then
cmd1_follows_cmd
else
cmd_when_all_failed
fi
- test
[ ] という記載方もある。
このときに] は意味をもたない。
以下の2つの例はまったく同じ意味を持つ。
例:test
if test "$str1" = "$str2"
then
command
fi
例: [ ]
if [ "$str1" = "$str2" ]
then
command
fi
[ の後にはスペースが必要なことに気をつける。
test コマンドの表現には以下の種類があることに気をつける。
tbd
互換性を保つためにはPOSIX の対応があるもののみにすること。
特にtest コマンドのand or をしめす-a -o は互換性がない機種があるために、
シェルの演算子&& || を使うほうが望ましい。
例:
if [ -f "$file" ] && ! [ -w "$file" ]
then
# $file は通常のファイルとして存在しているが、書き込み不可能。
echo $0: $file is not writable.
exit 1
fi
引数はtest コマンドに必須。
すべての引数は2重引用符で囲んで記述する必要がある。
こうすることで必ず引数を渡すことができる。
if [ -f "$file" ] ... OK
if [ -f $file ] ... NG
文字列の比較時に変数の中身が空だったりマイナスだと動作がおかしくなるときがある。このため if [ "X$file" = "Xyes" ] ... など接頭詞をつけてワークアラウンドをとることがある。
またネットワークごしでは権限に関するエラーが起こりやすいので気をつけること。対応策としてはcat が成功したかどうかで成功したかどうかを見るエラー処理くらいしかないとのこと。
またtest コマンドは整数のみしか使えない。(拡張版もあるが移植性のため、整数がよい。)
-
-
case 文をshellscript で使用する。
case ${PARAM} in
VAL_A) INSTRUCTION_A;;
VAL_B) INSTRUCTION_B;;
VAL_C) INSTRUCTION_C;;
,,,,
*) echo "ERROR"
exit 1 ;;
esac
実例
#!/bin/sh
echo " 業務メニュー"
echo ""
echo " 1. ユーザーの登録・削除"
echo " 2. WEBサーバ再起動"
echo " 3. 電源シャットダウン"
echo ""
echo -n " 番号を入力===> "
read menuno
case ${menuno} in
1) adduser ;;
2) apachectl graceful ;;
3) shutdown -h now ;;
*) echo "メニュー番号が違います。"
exit 1 ;;
esac
exit 0
例の参照元
実践!シェルスクリプト教室 2004/03/22(1文字取得スクリプトあり)
実践!シェルスクリプト教室 2004/03/08
- 変数展開
変数は中括弧を用いることで文字列との区別ができる。
例:
${EXAMPLE_VALUE}
また宣言されていない変数は空文字(null) に変換される。
以下のようなプログラムではトラブルにあうので注意が必要。
rm -rf /$TARGET
$TARGET 変数が存在しないときには、システムが消去されてしまう。
- 値を置き換える演算子
以下のような演算子が存在する。
演算子
|
処理
|
${varname:-word}
|
varname という演算子が存在し、かつnull 出ない場合にはその値を返す。
目的は変数に規定値を与えるため。
例:count という変数が定義されていないときに0を返す。
${count:-0}
|
${varname:=word}
|
varname という演算子が存在し、かつnull 出ない場合にはその値を返す。
目的は変数に規定値を与えるため。
例:count という変数が定義されていないときに0を返す。
${count:=0}
|
${varname:?word}
|
varname という演算子が存在し、かつnull 出ない場合にはその値を返す。
そうでない場合にはシェルスクリプトを強制終了する。
ただし対話的なシェルではそうとは限らない。
目的は変数が定義されていないときの予期しないエラーを回避するため。
例:count という変数が定義されていないときに警告を返す。
${count:?"undefined"}
|
${varname:+word}
|
varname という演算子が存在し、かつnull 出ない場合にはword を返す。
目的は変数に規定値を与えるため。
例:count という変数が定義されていないときに1を返す。
${count:+1}
|
- マッチングのための演算子
以下の例で変数path には以下の文字列が入っているものとしている。
/home/tolstoy/mem/long.file.name
演算子
|
処理
|
${valiable#pattern}
|
変数の値の先頭にパターンがマッチした場合、マッチする最短の文字列を削除して残りの部分を返す。
例:
${path#/*/}
結果:
tolstoy/mem/long.file.name
|
${valiable##pattern}
|
変数の値の先頭にパターンがマッチした場合、マッチする最長の文字列を削除して残りの部分を返す。
例:
${path##/*/}
結果:
long.file.name
|
${valiable%pattern}
|
変数の値の末尾にパターンがマッチした場合、マッチする最短の文字列を削除して残りの部分を返す。
例:
${path%/*/}
結果:
/home/tolstoy/mem/long.file
|
${valiable%%.*}
|
変数の値の末尾にパターンがマッチした場合、マッチする最長の文字列を削除して残りの部分を返す。
例:
${path%%.*}
結果:
/home/tolstoy/mem/long
|
- 文字列の長さを調べるための演算子
${#variable}
使い方としては以下のように用いる。
$ x=temporary_test_value
$ echo $x letter number is ${#x}.
temporary_test_value letter number is 20.
- 位置パラメータ
コマンドライン引数にアクセスする。
シェルの関数が呼び出されたときの引数にもアクセスする。
echo $1
echo ${12}
また、位置パラメータにも変数展開を適用できる。
- shift コマンド
位置パラメータの値が左方向にひとつずらされる。
つまり$1 にセットされていた値は削除され、$2 の値がセットされる。
同様に$2 にセットされていた値は削除され、$3 の値がセットされる。
・・・
この際に変数$# の値はひとつ減る。
shift には引数を指定することもでき、この場合には位置パラメータが
指定された数だけずらされる。
したがって引数なしでshift を実行した場合と引数つきで
shift 1 を実行した場合の処理結果は同じことになる。
- POSIX で定義されたシェル組み込みの変数
変数名
|
意味
|
$#
|
現在のプロセスに与えられた引数の数をあらわす。
|
$@
|
現在のプロセスに与えられた引数の数をあらわす。
二重引用符で囲まれている場合はそれぞれの引数の値を正確にあらわすように展開される。
|
#*
|
現在のプロセスに与えられた引数の数をあらわす。
二重引用符で囲まれている場合は連結されてひとつの変数へと展開される。
|
$-
|
シェルを起動する際に指定されていたオプションをあらわす。
|
$?
|
直前のコマンドの終了ステータスをあらわす。
|
$$
|
シェルのプロセスIDを示す。
|
$0
|
シェルのプログラム名を示す。
|
$!
|
最後にバックグラウンドで実行されたコマンドのプロセスIDをあらわす。
この値を後でwait コマンドの中から使いたい場合などに使用する。
|
$ENV
|
対話的なシェルが新しく起動される際のみ使われる。
この値を変数展開した結果がシェルの起動時に読み込まれるファイル名として使われる。XSI(X/Open System Interface) で定義されている。
|
$HOME
|
ユーザのホームディレクトリを表す。
|
$IFS
|
フィールドの区切り文字を示す。通常はスペース、タブ、改行文字。
|
$LANG
|
ロケール名の規定値を表す。
LC_ ではじまる
|
T.B.D
|
|
|
|
- 算術展開
tbd
- 変な回答例のおかしな数字
42
google でも「人生、宇宙、すべての答え」といれると42が出てくるそうな。
- シェルスクリプトのコンパイル
不明・できない?
$ command ????
-
- 2006/09/05 追記
- 2006/07/17 新規作成・分岐版
|