すでにQiitaにもいくつか記事があるが 1、Bashでの各種の括弧はそれぞれ意味がある。
自分でも知らなかったBashの括弧もあったので、改めてまとめてみた。
なお、Bashの話ではあるが、Bourne shell(/bin/sh
)としても動くサンプルコードは sh
コードとしてある。
bracket [ ]
shからある伝統的なコマンドで、test
と等価。式の結果を、0が真、1が偽の真偽値で返す。
if
と組み合わせて用いることが多い。
そう、シェルでは[
はコマンドなのである。2
[
と]
の前後にはスペースが必要で、後続のコマンドがある場合は;
で終わらせなければならない。なぜなら前述のとおり [
はコマンドで、[
から ]
までが一連のコマンドと引数の組み合わせだからだ。(]
は必須な引数という位置付け)
if [ "x$1" = "x--help" -o "x$1" = "x-h" ]; then
show_help # help
fi
この場合の式で "x$1"
のように x
といれている(何の文字列でもいい)のは、例えば$1
が空文字列だった場合にエラーになるから。先人の工夫である。
なお、論理式は-a
や-o
を使う方法の他に、&&
や||
を使って表現することも可能。
ただ前者は優先順位はあるのだが、後者の場合はコマンドとして順に処理されるので優先順位がない。
if [ "x$OPT" = "x-h" -o "x$OPT" = "x--help" ]; then
help
fi
if [ "x$OPT" = "x-h" ] || [ "x$OPT" = "x--help" ]; then
help
fi
# if を無くした形
[ "x$OPT" = "x-h" ] || [ "x$OPT" = "x-h" ] && help
double bracket [[ ]]
Bashになって 3 追加された条件式で、[ ]
の機能が拡張されたもの。
返す真偽値は同じだが、次の様な機能が追加されている。
( <EXPRESSION> ) 式のグループ化。優先される。
<EXPRESSION1> && <EXPRESSION2> 論理積。なお、従来の `-a` は使ってはいけない。
<EXPRESSION1> || <EXPRESSION2> 論理和。なお、従来の `-o` は使ってはいけない。
! <EXPRESSION1> 論理否定。
<STRING> == <PATTERN> 文字列比較。
<STRING> = <PATTERN> == と同じ。
<STRING> != <PATTERN> 文字列比較でマッチしていない場合に真。
<STRING> =~ <ERE> 拡張正規表現による文字列比較。
なお、正規表現を含む文字列比較は、[ ]
と違って式中で対象文字列を""で囲まなくてよい 4が、Shellにより解釈されて意図しない文字列に変換される可能性がある。なので、直接[[ ]]
中に正規表現を書くのではなく、変数を用いて比較すると良いだろう。
REGEXP="[hc]at"
[[ cat =~ $REGEXP ]] && echo "Matched"
parentheses ( )
サブシェル
丸かっこは、サブシェルで記述されたコマンドまたはコマンド群を実行する。
shからの機能である。
pwd
( cd /usr; pwd )
pwd # 最初の結果と同じ
コマンド実行
shで ` `
で実現していたコマンド実行を、 Bashでは $()
で表すことができる。
入れ子にもできるので便利。
SEED=$(expr $(date +%M) + $(date +%S))
echo $SEED
echo `date '+%Y/%m/%d'` # sh 方式も使える
関数
関数を宣言する場合に、関数名に()をつけて宣言する。
funcname() {
local FUGA
set -- $*
HOGE=$1
FUGA=$2 # FUGA はローカル変数
}
# Call
funcname
funcname "hoge" "fuga"
double parentheses (( ))
算術演算を表す。Cの形式の演算が使えたり5と、いろいろな式が使える。
echo $(( 0x10 )) # 16
echo $(( (2+3) * 5 / 2 )) # 12. 小数は表せない
if
の式として使えるが、[ ]
による式と違って、値が0
の時に偽値となる。
if ((0)); then
echo "true"
else
echo "false"
fi
# "false"
Cのようなforループも、表すことが可能。
for ((x=1; x<=3; x++))
{
echo $x
}
# Bash では、 do~done の代わりに、{~} が使える
braces { }
変数展開
変数名と文字列を区別する時に、変数名を明示的に指し示すために使う。
STR="user_${NAME}_logged_in!"
2桁以上の位置パラメータを表す時にも使う。
$ piyopiyo.sh "hoge" "fuga" 3 4 5 6 7 8 9 ten eleven
# $1 => hoge
# ${10} => ten
Bash独自の便利な変数展開もある。こちらの記事にまとめられている。
echo $HOGE # (null)
echo ${HOGE:-hoge} # hoge ... just behalf
echo $HOGE # (null)
echo $FUGA # (null)
echo ${FUGA:=fuga} # fuga
echo $FUGA # fuga ... also substituting value as deafult
コマンド群の実行
()
がサブシェルでコマンドを実行するのに対し、カレントシェルで(ブロック処理のように)一連のプログラムを実行できる。
出力内容は、纏めてリダイレクトなどが可能。
{
echo "PASSWD follows"
cat /etc/passwd
echo
echo "GROUPS follows"
cat /etc/group
} >output.txt
シンプルな例としては、関数での使用例。
help() {
echo "Usage: $0 [-h|--help]"
exit 255
}
ここに乗っていた Try-Catch ブロックの例。
try_catch() {
{ # Try-block:
eval "$@"
} ||
{ # Catch-block:
echo "An error occurred"
return -1
}
}
参考
ここのサイトが大変参考になった!
Bash Hackers Wiki - http://wiki.bash-hackers.org/start
-
例えばこちらの記事 https://qiita.com/yohm/items/3527d517768402efbcb6 ↩
-
/bin ディレクトリの中を確認してみよう ↩
-
BashはBourne Again Shellで、Bourne Shell(いわゆる
sh
)から拡張されたシェルである。 ↩ -
[a-z]
など、ローケルに少なからず影響されるので、POSIXクラスを使うと良いだろう。 (cf; https://ja.wikipedia.org/wiki/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE#%E6%A8%99%E6%BA%96 ) ↩