if,forなどのbashメモ

bash文法のメモ

忘れては調べるということの繰り返しが多いので、探しやすいように。

if文関連

if文の基本は、

# ifの基本
if 数値; then
    echo "trueのとき"
else if 数値; then
    echo "今度はtrueのとき"
else
    echo "今まですべてfalseだったとき"
fi

の形式で書く。数値が条件になっているが、コマンドを記述して返り値(ステータスコード)を使うことが多い。ステータスコードが0ならtrueとなる。testコマンドの略記コマンド[]をとてもよく使う印象がある。これを使うと、

# []をつかう
if [ 3 -eq 4 ]; then
    echo "ここは実行されないよ"
else
    echo "ここが実行されるよ"
fi

などになる。[]前後にはスペースが必要であることを忘れないように。

基本的にはifの条件式は[ 条件式 ]で書いていく。[[]](())などもあるけど、自分もよくわかってないので参考というかドキュメントのリンクを置いておく。

また、[]の中で!をつけておくと真偽値はひっくり返ることになる。

# ifで!をつかう
if [ ! 3 -eq 4 ]; then
    echo "ここが実行されるよ"
fi

test,[]コマンドなどの条件式については、Bash / Bash Conditional Expressions — DevDocsを見ると詳細が載っている。

以降は、ifの条件式として、数値や文字列、ファイルやディレクトリの存在チェックなどでよく使うものをそれぞれ記しておく。先ほどの参考にも載っている。

文字列関連

表にて。

条件式 内容
-z str 文字列strの長さが0である(zero)なら真
-n str 文字列strの長さが0でない(non-zero)なら真
string 文字列stringの長さが0でないなら真
s1 == s2 2つの文字列s1,s2が同じなら真
s1 != s2 2つの文字列s1,s2が異なるなら真
s1 < s2 文字列s1が文字列s2より辞書順で前なら真
s1 > s2 文字列s1が文字列s2より辞書順で後ろなら真

===でもいいらしい。===では右側にパターンマッチングを利用できるようだ。詳細は、Bash / Conditional Constructs — DevDocsにて。

数値関連

表にて。真ん中の演算子が違うだけ。

条件式 内容
a1 -eq a2 2つの整数値a1,a2が等しいなら真
a1 -ne a2 2つの整数値a1,a2が等しくないなら真
a1 -lt a2 pythonなどでいうa1 < a2
a1 -le a2 pythonなどでいうa1 <= a2
a1 -gt a2 python...a1 > a2
a1 -ge a2 python... a1 >= a2

Less ThanGreater than or Equalで覚えていれば問題ない。

ステータスコードのチェックにも使える。

ファイル関連

表にて。ファイル関連はたくさんある。

条件式 内容
-a file fileが存在すれば真。ディレクトリでもOK
-d file fileがディレクトリで存在すれば真
-e file fileが存在すれば真。ディレクトリでもOK。-aと同じ?
-f file fileが一般ファイルで存在すれば真

以上がもっともよく使いそうな4種。

他には、-b-cもあるけどspecial fileというのがわからない。デバイスファイルあたりが関係してるようだ。また、rwxなどのファイルの属性のチェックもできる。詳しくは、Bash / Bash Conditional Expressions — DevDocsにて。

for文関連

次はfor文。基本は、

for ((i=0; i<10; i++)); do
    echo $i
done

だが、もう一つの基本であるfor inを使うことがほとんど。

for i in {0..10}; do
    echo $i
done
for i in aa bb cc; do
    echo $i
done

bashでは{x..y}xからyまで辞書的な順番で展開してくれる機能があるようだ。便利でfor以外でも使える。

後者のようにしても問題ない。inの後ろは何かで括らなくてもいい。

lsとgrepからの配列をループ

これを書いておきたい。よく使う。

カッコでくくるとスペース区切りの文字列が配列になることを利用する。

textfiles=($(ls somedir/ | grep -e .txt$))
for name in "${textfiles[@]}"; do
    echo ${name}
done

このようにすれば拡張子がtxtであるファイル名が列挙される。for inのところでダブルクォーテーションで囲むのは、文字列中にスペースがあるとそこで意図せずに区切られてしまうためらしい。あんまりファイル名でスペースがあるのは考えたくないが。

@と*の例

理解が浅いが実行するとわかって来るかと思って4種類試した。 配列に4つ要素を含めている。takotabu"kako mare"tasuの4つ。

~ $ for i in ${arr1[@]}; do echo $i; done
tako
tabu
"kako
mare"
tasu
~ $ for i in ${arr1[*]}; do echo $i; done
tako
tabu
"kako
mare"
tasu
~ $ for i in "${arr1[@]}"; do echo $i; done
tako
tabu
"kako mare"
tasu
~ $ for i in "${arr1[*]}"; do echo $i; done
tako tabu "kako mare" tasu

要するに""が囲まれたものがあるときはinの後ろも""で囲った方がいい。

*は配列の各要素ごとをさらにIFS変数の最初の文字で区切ってから展開する。

一方で@は配列の要素ごとに展開する。

ちなみにIFS変数は区切り文字のリストであり、指定しなければ<space><tab><newline>になる。なるほどこれらで区切られるのはそういうわけか。また、""で囲まれているのは区切られない。

その他詳細は、Bash / Arrays — DevDocsにて。

pythonでいうinput()

readを使って変数に入力された値を文字列として格納することができる。

echo -n "もしもし、何か打ち込んでみて。-->"
read var1
echo "read: ${var1}"

このようにして簡単に格納が可能。やろうとは思わないけど、あまり長い文字列は読み取るべきではないと思う。bashなら他の方法がたくさんある。

関数関連

うっかり忘れたときのためにこの辺りのことも書いておく。

定義は、

somefunc() {
    echo -n "yを押してエンター ->"
    read will
    [ $will = "y" -o $will = "yes" ]
    return $?
}

でできる。上の関数はyyesを押したら0を返すもの。呼び出すときに[]でチェックすれば使えると思う。 関数名の前にfunction をつけても問題ない。

ひとまずここまで

bashでは展開という概念が大事だと実感する。よく使う${}もたくさん使い方があるみたい。

何か追記があればここに追記する予定。長くなれば別で書こう。

以上です。


関連書籍(広告)

https://amzn.to/3gVAURW
タイトルとURLをコピーしました