Contents
基本文法
Hello World
echo "Hello World"
コメント
# comment
コマンドの連結
AND
先のコマンドが成功した場合のみ次のコマンドを実行する
command1 && command2
OR
先のコマンドが失敗した場合のみ次のコマンドを実行する
command1 || command2
変数
共通単値変数
- 宣言
i=0
- 代入
i=1
- 参照
echo $i
数値
- 四則演算
$(($num1 + $num2))
真偽値
真偽値はないので、次のようにして使用する。
- 数値版
# グローバルに宣言 TRUE=1 FALSE=0 # ... if [ "$bool" -eq "$TRUE" ]; then fi
- 文字列版
# ... if [ "$bool" = "TRUE" ]; then fi
順序配列
- 宣言
list=(1 2 3)
- 全要素表示
echo ${list[@]}
or
echo ${list[*]}
- 後方追加
list+=(4)
- 前方追加
list=(0 "${array[@]}")
- 代入
$list[$i]=100
- 配列長
${#list[@]}
- 参照
length=${#list[@]} for ((i=0;i<$length;i++)) { printf "${list[$i]}," } for next in ${list[@]}; do echo $next done
- 要素削除
要素の削除はunsetにより可能であるが、配列インデックスは変化しないので、削除した要素番号は欠番になる。
unset list[1]
つまり実質下記と同じである。
${list[1]}=""
for-eachループで参照した場合は欠番の要素はスキップされる。
- コピー
array2=(${array1[@]})
連想配列
多次元連想配列はできない
- 宣言
declare -A dictionary
or
declare -A dictionary=([a]=1 [b]=2)
- 初期化
dictionary=( ["a"]="1" ["b"]="2" )
or
dictionary=([a]=1 [b]=2)
- 代入
dictionary[c]=3
- 参照
echo ${dictionary[$key]}
- 順序参照
for key in ${!dictionary[@]}; do echo ${dictionary[$key]} done
- 存在確認
※-nでは常にtrueとなる
if [ ! -z ${dictionary[$key]} ]; then fi
否定(存在しない場合)
if [ -z ${dictionary[$key]} ]; then fi
- 削除
unset dictionary[key]
- コピー
コピーはできない
比較演算
数値一致
$int1 -eq $int2
数値不一致
$int1 -ne $int2
数値 >
if [ $int1 -gt $int2 ]; then fi
数値 >=
if [ $int1 -ge $int2 ]; then fi
数値 <
if [ $int1 -lt $int2 ]; then fi
数値 <=
if [ $int1 -le $int2 ]; then fi
文字列一致
if [ "$str1" = "$str2" ]; then fi
文字列不一致
if [ "$str1" != "$str2" ]; then fi
正規表現一致
if [ "`echo $str | egrep "$regex"`" != "" ]; then fi
文字列長が0
if [ -z $str ]; then fi
文字列長が0より大きい
if [ -n $str ]; then fi
OR
$int1 -eq $int2 -o $int3 -eq $int4
AND
$int1 -eq $int2 -a $int3 -eq $int4
NOT
! $int1 -eq $int2
検査
読み込み可能
if [ -r $file ]; then fi
書き込み可能
if [ -w $file ]; then fi
実行込み可能
if [ -x $file ]; then fi
ファイル、ディレクトリ問わず何らかが存在する
if [ -e $file ]; then fi
ファイルが存在する
if [ -f $file ]; then fi
ディレクトリが存在する
if [ -d $file ]; then fi
シンボリックリンクが存在する
if [ -L $file ]; then fi
サイズが0より大きい
if [ -s $file ]; then fi
前者のファイルが後者のファイルより新しい
if [ $file1 -nt $file2 ]; then fi
前者のファイルが後者のファイルより古い
if [ $file1 -ot $file2 ]; then fi
制御構文
for
for ((i=0 ; i<10 ; i++)) { echo $i }
- 変数二つ
for ((i=0,j=0 ; i<10 ; i++,j=i*2)) { echo $i }
for each
- 配列変数から
for next in ${list[@]}; do echo $next done
- コマンド結果から
IFS_ORIGIN=$IFS IFS=$'\n' for next in `ls -l`; do echo $next done IFS=$IFS_ORIGIN
or
IFS_ORIGIN=$IFS IFS=$'\n' RESULT=`ls -l` for next in $RESULT; do echo $next done IFS=$IFS_ORIGIN
while
while [ $i -lt 10 ]; do echo $i i=`expr $i + 1` done
break
break
continue
continue
if
if [ "$num" -eq 10 ]; then echo "10" fi if [ "$str" = 10 ]; then echo "10" fi
if else
if [ "$num" -eq 10 ]; then echo "10" elif [ "$num" -gt 10 ]; then echo "> 10" else echo "false" fi
switch case
case $str in ABC|CDE) echo "ABC or CDE" ;; XXX) echo "XXX" ;; *) echo "Other" ;; esac
exit
exit [0,1]
シェルスクリプトを直ちに終了する
正常終了の場合、0を返すとよい。
異常終了の場合、1を返すとよい。
文字列操作
文字列長
${#str}
連結
concat=$str1$str2
分割
空白区切りの場合、次で分割できる
array=($str)
部分切り取り
str=`echo $str | cut -c <開始番号>-<終了番号>`
文字番号は1から始まる
置換
$str=`echo $str | sed -r "s/<正規表現>/<置換後文字列>/g"`
関数
定義
<関数名> () { <関数内処理> }
※引数がある場合でも()内は空でよい
呼び出し
<関数名> [<引数1>, ...]
引数使用
$1, $2, ~ $N
- 引数全体
$*
- 引数の数
$#
返り値
返り値はグローバル変数を使用する
returnコマンドにより、終了コードを整数で返すことは可能。
その場合は通常のコマンド実行と同じく、$?により終了コードを取得する。
コマンドライン引数
$1, $2, ~ $N
- スクリプト名
$0
- 引数全体
$*
- 引数の数
$#
- プロセス番号
$!
- パイプを使用可能にする場合
- パイプか引数のいずれかのみ
パイプで引数を受け取った場合は標準入力より取得する。
ARGSには空白か改行で区切られた文字列が代入される。
if [ -p /dev/stdin ]; then ARGS=(`cat -`) else ARGS=(`echo $@`) fi
- パイプか引数のいずれかのみ
- パイプと引数の両方を使用する
※パイプで与えられた値はコマンドライン引数の後に連結される
ARGS=($@) if [ -p /dev/stdin ]; then ARGS+=(`cat -`) fi
テキストファイル操作
リード
while read line; do echo $line done < <ファイルパス>
ライト
- 新規書き込み
echo $value > <ファイルパス>
- 追記
echo $value >> <ファイルパス>
Tips
処理するシェルの指定
#!/bin/bash
date
日付を数値として取得する
date +"%Y%m%d"
時間を含めて数値として取得する(ナノ秒は%N)
date +"%Y%m%d%H%M%S"
連想配列に配列を代入
declare -A dictionary list=(1 2 3) dictionary[a]=${list[@]} list=(4 5 6 7) dictionary[b]=${list[@]} # 連想配列長 echo ${#dictionary[@]} # 配列要素を出力(実態は空白区切りの一行文字列) echo ${dictionary[a]} # 配列取り出し list=(${dictionary[a]}) # 配列長を出力(一旦配列取り出しが必要) echo ${#list[@]} # 配列要素を出力 echo ${list[@]} # 配列要素を出力(実態は空白区切りの一行文字列) echo ${dictionary[b]} # 配列取り出し list=(${dictionary[b]}) # 配列長を出力(一旦配列取り出しが必要) echo ${#list[@]} # 配列要素を出力 echo ${list[@]}
コマンド実行結果の成否で分岐処理
<コマンド> > /dev/null 2>&1 if [ $? -eq 0 ]; then echo success else echo failure fi
コマンドの終了コードを取得する
RET_CODE=`echo $?`
複数のホストにpingを行うスクリプト
#!/bin/bash COMMAND_SUCCEEDED=0 COMMAND_FAILED=1 ListFile=list if [ "$1" != "" ]; then ListFile=$1 fi if [ ! -f $ListFile ]; then echo "No List File "$ListFile echo "Make IP or Hostname List File" echo "ex." echo "10.0.0.1" echo "10.0.0.2" echo "10.0.0.3" fi list=`cat list` echo Press Ctrl+C Twice to Stop echo ------------------------------- for ((;;)) { date +"[[%H:%M:%S]]" before=`date +%s` for next in ${list[@]}; do ping $next -c 1 -W 1 -f 2>&1 > /dev/null returnCode=`echo $?` if [ $returnCode -eq $COMMAND_SUCCEEDED ]; then printf $next"\t"OK"\n" else printf $next"\t"xxx"\n" fi done for ((;;)) { after=`date +%s` if [ "$before" != "$after" ]; then break fi sleep 0.1 } echo ------------------------------- }
色付きで出力する
PRINT_COLOR_GREEN="\e[32m" PRINT_COLOR_RED="\e[31m" PRINT_COLOR_DEFAULT="\e[m" printf $PRINT_COLOR_RED echo "red" printf $PRINT_COLOR_DEFAULT
サブシェルの中で異常終了
異常終了にexitコマンドを使用していると、”.”や”source”サブシェルとして呼び出した際に呼び出し元の親シェルまで終了してしまう。
これを防ぐにはreturnコマンドを使用する。
ただし、関数の中でreturnコマンドを呼ぶと関数が終了するだけなので、関数外でreturnコマンドを呼ぶ必要がある。
returnコマンドの引数はexitコマンドと同じであり、通常は正常終了の場合は0を引数に、異常終了の場合は1を引数に取る。
“sh”コマンドや”bash”コマンドでサブシェルを呼び出している場合は反対にreturnでサブシェルを終了しようとするとエラーになる。exitで終了しなければならない。
無限ループで実行
1秒待機で実行。マイクロ秒で待機したい場合は、usleepを使用する。
while [ 1 ]; do date time <処理内容> echo echo echo sleep 1 done
ftp
ftp操作の基本形
SERVER=10.0.0.1
USER=user
PASSWORD=password
ftp -n <<END open $SERVER user $USER $PASSWORD <ftpコマンド1>
<ftpコマンド2>
<ftpコマンド3>
<...> END
ftpコマンド
- 一覧取得
ls [<パス>]
- ディレクトリ移動
cd <パス>
- ファイルの取得
ローカルの配置パスは指定できず、カレントディレクトリとなるget <パス>
- 複数のファイルの取得
ローカルの配置パスは指定できず、カレントディレクトリとなるmget <パス> [...]
- ファイルの設置
put <パス> [<設置ファイル名>]
- 複数のファイルの設置
mput <パス> [...]
- ファイルの削除
delete <パス>
- 複数のファイルの削除
mdelete <パス> [...]
- ディレクトリの作成
mkdir <パス>
- ディレクトリの削除
rmdir <パス>