[トップページ] [星雲紀行] [MLXS] [WPGen] [自作音楽] [モデル] [vi/vim] [tips] [自己紹介]

shell script

目次

  1. はじめに
  2. シェルスクリプトの書式
  3. 制御演算子
    1. ヒアドキュメント
  4. ループ
    1. 例
      1. シンプルなループ例
      2. 無限ループ
  5. 条件分岐
    1. if
    2. case
  6. 変数と演算子
  7. memo
  8. 参考文献・参考ウェブページ
  9. 履歴

はじめに

このページはシェルスクリプトについて記載しています。
shell script はbash やcsh などのshell で使用できるスクリプト。
作業の自動化などに効率が良い。

  • 文字列処理はシェルスクリプトの優れた利点。 他の言語では非常に面倒になってしまう。
    何かの区切り文字をつかって各フィールドを区切ることはきわめて重要。 タブ、カンマ、コロン などの実際のデータ中で使用されない文字を使えば十分。
    また、再利用性を高めるために、元のデータの持っていたデータの構造をできるだけ残すべき。
    最近はXML によるデータの一般化が進んでいるので非常に有効である。
[content]

シェルスクリプトの書式

  • ファイルの先頭文字を#! とすると先頭行の残りの文字列を インタプリタへのパス名とみなす。 オプションはひとつだけ指定が可能。標準は/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

中央大学シェルスクリプト説明ウェブページ[シェルの置換機能]

[content]
シンプルなループ

ディレクトリ内部のすべてのzip ファイルを展開する。

$ for i in *.zip; do unzip $i; done
[content]
無限ループ

#!/bin/sh
while /bin/true	# 無限ループ
do
    echo ""
    date
    ps -ef | grep apache2
    sleep 1		# 延々と実行しないように休みを入れる
done

[content]

条件分岐

[content]

if

  • 分岐命令 通常
    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 コマンドは整数のみしか使えない。(拡張版もあるが移植性のため、整数がよい。)
[content]

case

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

[content]

変数と演算子

  • 変数展開
    変数は中括弧を用いることで文字列との区別ができる。
    例:
    ${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

memo

  • 変な回答例のおかしな数字
    42
    google でも「人生、宇宙、すべての答え」といれると42が出てくるそうな。
  • シェルスクリプトのコンパイル
    不明・できない?
    $ command ????

参考文献・参考ウェブページ

[content]

履歴

  • 2006/09/05 追記
  • 2006/07/17 新規作成・分岐版
[content]
ご意見、ご感想、誤字、間違い等、お気づきの点がありましたら KGussan@Gmail.com まで連絡ください。
このウェブページの注意・免責事項 Copyright (C) 2004-2012 KGussan. [トップページ]
[PR:元国税局勤務の起業家向け、遺産相続の相談なら植村洋税理士事務所:一時間無料税理士相談。お気軽に。]