マニュアル: Bash

投稿日: 更新日:

ShellCheckを使おう

以下のサイト/プログラムで、シェルスクリプトの文法をチェックしてくれます。

起動オプション

man bashしたあとすぐ先にあるOPTIONSを参照。

  • '-c string': コマンドを文字列から取得
  • '-l': ログインシェルとして実行

set

起動オプションには、setで指定できるオプションも使えます。 setはビルドインコマンドで、説明を見るには、man bashしたあと、 /^SHELL BUILTIN COMMANDSと入力するのが楽です。

  • -e: exit 0以外になったときに停止
  • -u: 未定義変数を使用した時に停止
  • -x: 実行するコマンドを画面に出力する。

コマンドの結果代入は$(...)を使う

コマンドの結果を代入する方法にはバッククォートを使う方法と、 $(...)を使う方法がありますが、$(...)を使うようにした方がいいです。

その理由は以下に書かれています。

BashFAQ/082 - Greg's Wiki

POSIX標準にも含まれており、bash, dash(Debian), busyboxなどでも使えるため、 互換性の問題もありません。

変数展開

以下は、次のシェルで確認しています。

  • GNU bash 3.2.57(macOS High Sierra)
  • Busybox 1.27.2-r7(Alpine Linux 3.7.0)
  • Debian Almquist Shell(dash, Debian 9.4) ※一部のみ

未定義、空の場合の定義

  • ${parameter:-word}: 未定義もしくはnullの場合、wordが使用される。
FOO=foo
echo ${FOO:-bar} # => foo

FOO=
echo ${FOO:-bar} # => bar

unset FOO
echo ${FOO:-bar} # => bar
  • ${parameter:=word}: 未定義もしくはnullの場合、wordが使用され、代入される
FOO=foo
echo ${FOO:=bar} # => foo

FOO=
echo ${FOO:=bar} # => bar
echo ${FOO}      # => bar

unset FOO
echo ${FOO:=bar} # => bar
echo ${FOO}      # => bar
  • ${parameter:?word}: 未定義もしくはnullの場合、標準エラー出力にwordが出る。
FOO=foo
echo ${FOO:?foo is undefined} # => foo
echo $?                       # => 0

FOO=
echo ${FOO:?foo is undefined} # => FOO: foo is undefined
echo $?                       # => 1(bash, dash), 2(busybox)

unset FOO
echo ${FOO:?foo is undefined} # => FOO: foo is undefined
echo $?                       # => 1(bash, dash), 2(busybox)
  • ${parameter:+word}: 未定義もしくはnullのときは何もせず、それ以外のときはwordに置き換えられる。
    • nullは空文字のことだと思いますが、なぜか置換されますね。。。
FOO=foo
echo ${FOO+bar} # => bar

FOO=
echo ${FOO+bar} # => bar

unset FOO
echo ${FOO+bar} # => (なし)

部分文字列

  • ${parameter:offset}: offset文字目から後を出力する。
  • ${parameter:offset:length}: offset文字目から後を出力する。
  • 最初の文字は、offset=0となる。
  • offsetに負の値を指定すると、後ろから取得する。ただし、コロンとマイナスの間にスペースを入れること
FOO=foo.tar.gz
echo ${FOO:4}     # => tar.gz
echo ${FOO: -6}   # => tar.gz
echo ${FOO:4:3}   # => tar
echo ${FOO: -6:3} # => tar

単語の長さ

  • ${#parameter}: 変数の長さを出力する。
FOO=foo.tar.gz
echo ${#FOO} # => 10

単語の削除

  • ${parameter#word}: wordを前方から最短一致で削除する。
  • ${parameter##word}: wordを前方から最長一致で削除する。
  • ${parameter%word}: wordを後方から最短一致で削除する。
  • ${parameter%%word}: wordを後方から最長一致で削除する。
FOO=foo.tar.gz
echo ${FOO#*.}  # => tar.gz
echo ${FOO##*.} # => gz
echo ${FOO%.*}  # => foo.tar
echo ${FOO%%.*} # => foo

単語の置換

  • ${parameter/pattern/string}: 最長一致でpatternをstringで置き換える
FOO=foo.tar.tar.tar.gz
echo ${FOO/gz/bz}   # => foo.tar.tar.tar.bz
echo ${FOO/t*r/bar} # => foo.bar.gz

条件式

数値は「以上」「以下」などを使用するためアルファベット(eqなど)を使い、 文字列はその必要がないから、=を使うと覚えるといいかも。 (でも辞書順の比較はありますね)

  • 条件: if, elif, else, fiifより)
  • 論理演算子: and -> -a, or -> -o(testより)
  • 文字列の比較(6.4 Bash Conditional Expressionsより)
    • 等しい: = (推奨)または ==
      • = が推奨なのはPOSIX準拠のため。
    • 等しくない: !=
  • 数値の比較: -eq, -ne, -lt, -le, -gt, -ge (6.4 Bash Conditional Expressionsより)
  • -e file: ファイルが存在すればtrue

case

case

以下のような感じで書きます。

  • *): defaultに相当
  • ;;: breakに相当
  • 終わりはesac(caseの逆)
case $VAL in
  a | b)
    ...
    ;;
  c | d)
    ...
    ;;
  *)
    ...
    ;;
esac

引数の解析

ビルドインコマンドにgetoptsがある(未調査)。

変数が定義されているかどうかのチェック

以下のようにすればよい。この場合、VALが未定義の場合は '-' 以降、すなわち空文字になる。

if [ "${VAL-}" = "" ]

set -u してるときに変数が未定義または空文字かチェックする for RHEL/CentOS 6 - Qiita

「シェルスクリプト基本リファレンス」のp187に説明がある。

  • ${パラメータ:-値}: パラメータが未定義もしくは空の場合、指定された値に展開される。
  • ${パラメータ-値}: パラメータが未定義の場合、指定された値に展開される。

自分自身のパスに移動

# change to topdir
cd `dirname $0`

古い環境での注意点

3系列のときは、配列が使えなかったはず。

コマンドでエラーが出ても続行

bash スクリプトの先頭によく書く記述のおさらい | Money Forward Engineers' Blog

command || true

公式サイト