206
185

More than 1 year has passed since last update.

Bashの括弧のノウハウ(まとめ)

Last updated at Posted at 2018-08-22

すでにQiitaにもいくつか記事があるが 1、Bashでの各種の括弧はそれぞれ意味がある。
自分でも知らなかったBashの括弧もあったので、改めてまとめてみた。

なお、Bashの話ではあるが、Bourne shell(/bin/sh)としても動くサンプルコードは sh コードとしてある。

bracket [ ]

shからある伝統的なコマンドで、test と等価。式の結果を、0が真、1が偽の真偽値で返す。
if と組み合わせて用いることが多い。
そう、シェルでは[はコマンドなのである。2
[] の前後にはスペースが必要で、後続のコマンドがある場合は;で終わらせなければならない。なぜなら前述のとおり [はコマンドで、[ から ] までが一連のコマンドと引数の組み合わせだからだ。(]は必須な引数という位置付け)

sh
if [ "x$1" = "x--help" -o "x$1" = "x-h" ]; then
  show_help    # help
fi

この場合の式で "x$1" のように x といれている(何の文字列でもいい)のは、例えば$1が空文字列だった場合にエラーになるから。先人の工夫である。

なお、論理式は-a-oを使う方法の他に、&&||を使って表現することも可能。
ただ前者は優先順位はあるのだが、後者の場合はコマンドとして順に処理されるので優先順位がない。

sh
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 追加された条件式で、[ ]の機能が拡張されたもの。
返す真偽値は同じだが、次の様な機能が追加されている。

bash
( <EXPRESSION> )                    式のグループ化。優先される。
<EXPRESSION1> && <EXPRESSION2>      論理積。なお、従来の `-a` は使ってはいけない。
<EXPRESSION1> || <EXPRESSION2>      論理和。なお、従来の `-o` は使ってはいけない。
! <EXPRESSION1>                     論理否定。
<STRING> == <PATTERN>               文字列比較。
<STRING> = <PATTERN>                == と同じ。
<STRING> != <PATTERN>               文字列比較でマッチしていない場合に真。
<STRING> =~ <ERE>                   拡張正規表現による文字列比較。

なお、正規表現を含む文字列比較は、[ ]と違って式中で対象文字列を""で囲まなくてよい 4が、Shellにより解釈されて意図しない文字列に変換される可能性がある。なので、直接[[ ]]中に正規表現を書くのではなく、変数を用いて比較すると良いだろう。

bash
REGEXP="[hc]at"
[[ cat =~ $REGEXP ]] && echo "Matched"

parentheses ( )

サブシェル

丸かっこは、サブシェルで記述されたコマンドまたはコマンド群を実行する。
shからの機能である。

sh
pwd
( cd /usr; pwd )
pwd       # 最初の結果と同じ 

コマンド実行

shで ` ` で実現していたコマンド実行を、 Bashでは $() で表すことができる。
入れ子にもできるので便利。

bash
SEED=$(expr $(date +%M) + $(date +%S))
echo $SEED

echo `date '+%Y/%m/%d'`        # sh 方式も使える

関数

関数を宣言する場合に、関数名に()をつけて宣言する。

sh
funcname() {
    local FUGA
    set -- $*
    HOGE=$1
    FUGA=$2    # FUGA はローカル変数
}

# Call
funcname
funcname "hoge" "fuga"

double parentheses (( ))

算術演算を表す。Cの形式の演算が使えたり5と、いろいろな式が使える。

bash
echo $(( 0x10 ))             # 16
echo $(( (2+3) * 5 / 2 ))    # 12. 小数は表せない

if の式として使えるが、[ ] による式と違って、値が0の時に偽値となる。

bash
if ((0)); then
  echo "true"
else
  echo "false"
fi
# "false"

Cのようなforループも、表すことが可能。

bash
for ((x=1; x<=3; x++))
{
  echo $x
}
# Bash では、 do~done の代わりに、{~} が使える

braces { }

変数展開

変数名と文字列を区別する時に、変数名を明示的に指し示すために使う。

sh
STR="user_${NAME}_logged_in!"

2桁以上の位置パラメータを表す時にも使う。

sh
$ piyopiyo.sh "hoge" "fuga" 3 4 5 6 7 8 9 ten eleven
# $1    => hoge
# ${10} => ten

Bash独自の便利な変数展開もある。こちらの記事にまとめられている。

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

コマンド群の実行

() がサブシェルでコマンドを実行するのに対し、カレントシェルで(ブロック処理のように)一連のプログラムを実行できる。
出力内容は、纏めてリダイレクトなどが可能。

sh
{
  echo "PASSWD follows"
  cat /etc/passwd
  echo
  echo "GROUPS follows"
  cat /etc/group
} >output.txt

シンプルな例としては、関数での使用例。

sh
help() {
    echo "Usage: $0 [-h|--help]"
    exit 255
}

ここに乗っていた Try-Catch ブロックの例。

sh
try_catch() {
    { # Try-block:
        eval "$@"
    } ||
    { # Catch-block:
        echo "An error occurred"
        return -1
    }
}

参考

ここのサイトが大変参考になった!

Bash Hackers Wiki - http://wiki.bash-hackers.org/start


  1. 例えばこちらの記事 https://qiita.com/yohm/items/3527d517768402efbcb6 

  2. /bin ディレクトリの中を確認してみよう 

  3. BashはBourne Again Shellで、Bourne Shell(いわゆるsh)から拡張されたシェルである。 

  4. [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 ) 

  5. http://wiki.bash-hackers.org/syntax/arith_expr 

206
185
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
206
185