シェルスクリプトのメモ
シェルスクリプトを書く上で、よく忘れるのでメモ
動作はCentOS5 or RHEL5+Bash(Bourne-Again Shell)で確認。
○行説明(わかりづらかったので色付け)
スクリプト例
実行結果
○色々なメモ
- 1行目
スクリプトファイルの1行目は、スクリプト内の行を実行するプログラムを識別するために、カーネルによって使用される。
#!はマジックナンバーと呼ばれ、コメントではなく、実行環境の宣言になる。
ここではBashを使用するので、 #!/bin/sh と記述する。
ksh(korn shell)の場合なら #!/bin/ksh 等に置き換える。
- デバッグ
シェルスクリプトの文法エラー確認
-nのオプションを付けてシェルスクリプトを実行
エラーがない場合は何も表示されない。
例:
$ sh -n test.sh
-
シェルスクリプトのトレース
-xのオプションを付けてシェルスクリプトを実行
例:
○ test.sh(中身)export LANG=C
echo "test"
echo `date`○ シェルスクリプト実行結果
$ sh -x test.sh
+ export LANG=C
+ LANG=C
+ echo test
test
++ date
+ echo Sat Jan 1 00:00:00 JST 2000
Sat Jan 1 00:00:00 JST 2000※ export LANG=Cをしてるのは、ターミナル上で文字化けの回避
因みに、毎回トレースを入れるなら、マジックナンバー部分に
#!/bin/sh -x
としておけば普通に起動してもトレースモードになる。
○位置パラメータとコマンド行引数
- 位置パラメータ数を取得
$#
例:
○test.sh (中身)
#!/bin/sh
echo $#
○結果(1)$ sh test.sh 0
1○結果(2)
$ sh test.sh 0 1
2
○条件分岐
- if文
if 条件
then
コマンド
elif 条件
then
コマンド
else
コマンド
fi例:入力されたパラメータの入力値調査
val=$1
if [ ${val} -lt 1 ]
then
echo "入力値は1より小さい"
elif [ ${val} -eq 1 ]
then
echo "入力値は1"
else
echo "入力値は1より大きい"
fiもちろん、elif 条件ぬきでも書くことはできる。
- if文等使用時の演算子
数値比較
演算子 意味 -eq == equal 同じ -ne != not equal 違う -lt < less than 未満(より小さい) -gt > greater than より大きい -le <= less equal than 以下 -ge >= greater equal than 以上 英語で覚えるとわかりやすい。
文字列比較
演算子 意味 = 等しい != 等しくない (何故か先日ここでひっかかったので追加w)
例:文字列が等しいか
if [ ${str} = "test" ]
then
echo "ok"
else
echo "ng"
fi
ファイル属性演算子 意味 -d ディレクトリなら真を返す -f 通常ファイルなら真を返す -L シンボリックリンクなら真を返す -r 読み取り可能ファイルなら真を返す -w 書き込み可能ファイルなら真を返す -x 実行可能ファイルなら真を返す -s サイズが0より大きければ真を返す 例:カレントディレクトリ上に「test」ディレクトリが有るか
if [ -d test ]
then
echo "ok"
else
echo "ng"
fi※否定の場合は!を付ける
if [ ! -d test ]
then
echo "ok"
else
echo "ng"
fi
- 最後に実行したコマンドの終了ステータスを取得
$?
例:test.shというプログラムを走らせた結果で分岐
./test.sh
if [ $? -eq 0 ]
then
exit "ok"
else
exit "ng"
fi
- バックグラウンドに送った最後のジョブのPID値を取得
$!
例:a.shというプログラムをバックグラウンドで走らせてa.shのPIDを取得
./a.sh > /dev/null 2>&1 &
val=$!
echo ${val}
- シェルスクリプト(自プロセス)のPID値を取得
$$
○囲い文字
- 囲い文字
シングル?ダブル?それともバッククォート?
もち理解していますが、書いておきます
上にも出てきていますが、関数dateをechoして結果を変数に保存したりするとき、そのまま打つと
# echo date
date
そのまま出ちゃいます
では順にシングル、ダブル、バックとやってみましょう
○シングルクォート
# echo 'date'
date
○ダブルクォート
# echo "date"
date
○バッククォート
# echo `date`
Sat Jan 1 00:00:00 JST 2000
バッククォートの時が意図した処理になってあとは普通にdateという文字列表示です。
では次に、シングルとダブルの違い
変数に入れるのが面倒なのでLANG使わせてもらいましょう
○シングルクォート
# echo '${LANG}'
${LANG}
○ダブルクォート
# echo "${LANG}"
ja_JP.UTF-8
シングルの方は$変数を無視して表示です
ここを使い分けられるようになるとシェルスクリプトの幅が広がるので覚えちゃいましょう~
※${LANG}と記載していますが、$LANGでもいいです。
○番外編。
(プチ実用(?)シェルスクリプトのサンプル)
※いかなる責任も負えませんので、使用は自己責任でお願いします。
※ダウンロード用サンプルスクリプトはUTF-8 LFで作成しています。
-
デーモン動作チェックスクリプト
再起動直後ぐらいに実行すると良さそうなシェルスクリプト
例: デーモン動作チェックプログラム
原理は単純pidファイルを開いて、そのプロセスが生きているかどうか確認するだけ。
○proc_chk.sh (DL準備中。コピペしてくださいw)
※2010/06/22 更新#!/bin/sh
function proc_chk()
{
RES=0
chk_str=$1
if [ -f $2 ]
then
pid_file=`cat $2|sed s/' '//g`
if [ -d /proc/${pid_file} ]
then
RES=1
else
RES=0
fi
else
RES=0
fi
printStr=${chk_str}'########################'
STR_BUF=`echo ${printStr} | awk '{printf("%-20.20s",$1);}'|sed s/#/./g`
if [ ${RES} -eq 1 ]
then
echo "${STR_BUF}[ OK ]"
else
echo "${STR_BUF}[ NG ]"
fi
}
########################
#ここから下に調べたい物を記載。
# proc_chk デーモン名(何でもいい) PIDファイル
#Apache check
proc_chk Apache "/var/run/httpd.pid"
#ntpd
proc_chk ntpd "/var/run/ntpd.pid"
#sshd
proc_chk sshd "/var/run/sshd.pid"○結果
# ./check_proc.sh
Apache..............[ NG ]
ntpd................[ OK ]
sshd................[ OK ]※Apacheが落ちている例
個人的メモでは、awkの桁合わせ部分が覚えられないためのメモw
※postfix引っかける場合sed使わないとダメかも。 2010/06/22版で対策済み
プロポーショナルフォントだからずれて見えるけど、等幅フォントなら問題無し -
拡張子一括変換スクリプト
○ext_chg.sh (DL準備中。コピペしてくださいw)#!/bin/sh
#変更前拡張子
ext=".TXT"
#変更後拡張子
chext=".txt"
list=`ls`
for file in ${list}
do
chfile=`echo ${file}|sed "s/${ext}/${chext}/g"`
if [ ${file} != ${chfile} ]
then
mv ${file} ${chfile}
fi
done -
簡易CPU負荷チェックスクリプト
○loadaverage_chk.sh (DL準備中。コピペしてくださいw)
※現状では変数:min1のみ使用。min5とmin15は使っていません。
※crontabを使用してスクリプトを呼び出すと、定期監視になります。
※負荷が閾値を超えた場合メールがガンガン届くので注意してください。#!/bin/sh
#-------------------------------------------------------------------------------------------------#
#閾値
threshold=1
#宛先
toaddr=root@localhost
#送信元
fromaddr=alertmail@localhost
#-------------------------------------------------------------------------------------------------#
loadaverage=`uptime | awk '{print $8 $9 $10;}' | tr "," " "`
min1=`echo ${loadaverage} | cut -d" " -f1`
min5=`echo ${loadaverage} | cut -d" " -f2`
min15=`echo ${loadaverage} | cut -d" " -f3`
comp=`echo "scale=2; ${threshold} < ${min1}" | bc`
if [ ${comp} -eq 1 ]
then
mainmsg="サーバの負荷が閾値${threshold}を超え、${min1}になりました。"
echo "${mainmsg}"
echo "${mainmsg}" | /bin/mail -s "loadaverage alert" ${toaddr} -- -f ${fromaddr}
fi -
ftp通信スクリプト
※動作チェックはしましたが、運用チェックしてません。バグあったらごめんなさい。
○ftp_cron.sh (DL準備中。コピペしてくださいw)
※ざっくりと完成(2010/12/17 現在)
時々"ftp -n"と言うプロセスが残ったままになるようなのでpidを吐いてkillするようにしたものです#!/bin/sh
○ftpconnect.txt (FTPの通信内容)
# initialize ------------------------------------------
HOST_NAME="192.168.127.51"
FTP_PID_PATH="./ftppid/"
FTP_PID_FILE_NAME="ftp_`date +%Y%m%d%H%M%S`.pid"
KILL_DAY=1
# -----------------------------------------------------
#PID DIR CHECK
if [ ! -d ${FTP_PID_PATH} ]
then
mkdir ${FTP_PID_PATH}
fi
#FTP Connect
ftp -n ${HOST_NAME} < ftpconnect.txt &
#Write PID
echo $! > "${FTP_PID_PATH}${FTP_PID_FILE_NAME}"
#Delete PID file
FIND_FILE=`find ${FTP_PID_PATH} -type f -print`
for pidfile in ${FIND_FILE}
do
pid_res=`cat ${pidfile}`
ps_res=`ps aux | grep ${pid_res} | grep ftp | grep -v grep | wc -l`
if [ ${ps_res} -eq 0 ]
then
rm -f ${pidfile}
fi
done
#Kill deadprocess
FIND_FILE=`find ${FTP_PID_PATH} -type f -mtime +${KILL_DAY} -print`
for pidfile in ${FIND_FILE}
do
kill `cat ${pidfile}`
rm -f ${pidfile}
done
user test password
bin
lcd /var/www/html/
cd /ftproot/
get test.txt
bye※補足
接続ユーザ:test 、 パスワード:password で接続
毎回PIDを吐いて2日前のプロセスをkill。プロセスチェックで実態の無いPIDファイルは削除
![]() シェルの基礎 |
![]() Linux |
![]() シェルスクリプト:サンプル |