Paepoi

Paepoi » ShellScript Tips » ShellScript Tips | 条件分岐

ShellScript Tips | 条件分岐

# 最終更新日 2019.12.01

test コマンドと [[
test コマンドは真偽値を戻す、代わりに [...] を利用することもできる。
更に bash, zsh では [[...]] も使える、この三つは下記のような場合はまったく同じです。
if test 1 -ne 2; then
# ↓
if [ 1 -ne 2 ]; then
# ↓
if [[ 1 -ne 2 ]]; then

[[...]] はいったい何かというと [ の拡張と思えばいいようです。
#!/bin/sh

# = でパターンマッチ
[[ おまえはアホ = *アホ ]] && echo 1 || echo 2
#=> 1
[[ おまえはスケベ = *アホ ]] && echo 1 || echo 2
#=> 2

# =~ で正規表現マッチ、単なる文字列探しにも使える
[[ おまえはアホ =~ [(アホ|バカ)] ]] && echo 1 || echo 2
#=> 1
[[ おまえはスケベ =~ [(アホ|バカ)] ]] && echo 1 || echo 2
#=> 2

# 辞書順で文字列比較、数値優先には当然ならないけど
[[ test2.txt < test12.text ]] && echo 1 || echo 2
#=> 2

# 論理演算子が &&, || になる
[[ a = a && b = b ]] && echo 1
#=> 1

if
if については説明不要かと。
上記で既に書いていますが単純な if 文であれば &&, || のほうが簡単かつ明解です。
[[ 条件式 ]] && 真の場合 || 偽の場合
if [[ $PWD = $HOME ]]; then
    echo ホームです
else
    cd ~
fi

# ↓

[[ $PWD = $HOME ]] && echo ホームです || cd ~

ブレースでネストすることもできる。
ただし以下のような場合があるので注意。
#!/bin/sh

motor=スズキのバイクはかっこいい

[[ $motor =~ スズキ ]] && {
    [[ $motor =~ かっこいい ]] && echo ヨシ!
    [[ $motor =~ かっこわるい ]] && echo シネ!
} || {
    echo ダセーwwwww
}
ダセーwwwwwも表示されてしまうはずです。
上記のようにブレースはブロックスコープにならないので必ず or 演算もセットで使う。
何もしないならコロンを使うのが一番簡単。
[[ $motor =~ かっこわるい ]] && echo シネ! || :

elif を使う場合は素直に if を使ってください。
以下は条件式。

数値
条件式 意味
数値 -eq 数値==
数値 -ne 数値!=
数値 -ge 数値>=
数値 -gt 数値>
数値 -le 数値<=
数値 -lt 数値<
文字列
条件式 意味
-n 文字列文字列が一文字以上ある
-z 文字列文字列がゼロ文字
文字列1 = 文字列2等しい
文字列1 != 文字列2等しくない
ファイル
条件式 意味
-G ファイル名ファイルのグループが実行ユーザー
-O ファイル名ファイルの所有者が実行ユーザー
-S ファイル名ソケット
-b ファイル名ブロックデバイスファイル
-c ファイル名キャラクタデバイスファイル
-d ファイル名ディレクトリ
-e ファイル名存在確認
-f ファイル名通常ファイル
-g ファイル名SGID がある
-h ファイル名, -L ファイル名シンボリックリンク
-k ファイル名スティッキービットがある
-p ファイル名名前付きパイプ
-r ファイル名読み取り可能
-s ファイル名ファイルサイズがゼロではない
-t ファイル名端末でオープンされてい
-u ファイル名SUID がある
-w ファイル名書き込み可能
-x ファイル名実行可能
ファイル名1 -nt ファイル名2ファイル名1のほうが修正時刻が新しい
ファイル名1 -ot ファイル名2ファイル名1のほうが修正時刻が古い
ファイル名1 -ef ファイル名2デバイス番号と i ノード番号が同じ

特殊変数
特殊変数 解説
$n (数字)$0 はスクリプト名、以降 $1, $2…${10}, ${11}… と引数が並ぶ
$#引数の個数
$@$0 以外の全ての引数("$@" の場合 "$1" "$2" …")
$*$0 以外の全ての引数("$*" の場合 "$1 $2 …")
$?最後に実行したコマンドの終了ステータス
$!最後に実行したバックグラウンドコマンドの PID
$$シェルの PID
$-現在のオプションフラグ

以上がありますがほとんど引数のことですね。
こんなふうに使います。
#!/bin/sh

echo ディレクトリ名で圧縮します

if [[ $# -eq 0 ]]; then
    echo 引数が無いよ
else
    path=`pwd`
    name=${path##*/}
    file-roller --add-to="${name}.tar.gz" "$@"
fi

case
case 文は文字列が条件に一致するかで分岐する。
条件 意味
?一文字
*ワイルドカード
[...][...] に含まれる一文字
[!...][!...] に含まれない一文字
また条件を「|」記号で or 演算することもできる。
#!/bin/sh

case $USER in
    root|syacho)  echo おはようございます ;;
    sasakima-nao) echo おまえかよ ;;
    bite-*)       echo うぃーす ;;
    *)            echo 誰だヨ! ;;
esac

関数
シェルスクリプトも関数が作れます。

ただし C 言語の関数等と違い別プロセスとして実行されます。
親シェルの変数は参照できますが戻り値は $? を利用します。

関数の呼び出しに括弧は不要で引数は半角空白区切りで渡します。
関数側から引数を参照するには $1, $2... を利用、別プロセスなのでスクリプトの呼び出し引数とは違う。
等々、C 言語なんかを知っていると少し戸惑ってしまうと思います。
#!/bin/sh

your_motor_cycle() {
    if [[ $1 = スズキ ]]; then
        owner_var=かっこいい # 親の変数を参照できる
        return 0
    fi
    return 1
}

owner_var=ダサい!

# 関数呼び出し、引数は ISF 区切りで渡す
your_motor_cycle スズキ

# if test func みたいにできない
[[ $? ]] && echo $owner_var || echo 失敗
どうしても戻り値が欲しいならパイプを使う。
UNIX のコマンドが全部そうなっていることに気が付いたかな。
#!/bin/sh

suzuki() {
    echo $1カッコイイ
    return 0
}
suzuki スズキのバイクは | cat -n

# 変数に入れたい場合
car=`suzuki 車も`
echo スズキは$car

Copyright(C) sasakima-nao All rights reserved 2002 --- 2024.