LoginSignup
18
27

More than 5 years have passed since last update.

【初心者向け】if文、for文、while文を書くときのテンプレート【もう迷わない】

Last updated at Posted at 2017-03-04

Bash初心者のために、制御文(if文、for文、while文)の書き方をテンプレ化してみました。

ちなみにIFSの値は、こうなっていること前提です。

IFSの設定値(空白、水平タブ、LF)
$ printf "${IFS}" | od -An -tx1
 20 09 0a
bashのバージョン
$ bash --version
GNU bash, version 4.3.46(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

ふつうのフレンズたち

if文のフレンズ

if文のフレンズ
# 条件部がコマンド(一般形式)
if command; then
    echo hoge
elif command; then
    echo fuga
else
    echo hogefuga
fi

# true, falseコマンド
if true; then
    echo hoge
fi

# testコマンド
if [ 1 -eq 1 ]; then
    echo hoge
fi

# 複合コマンド([[]])
if [[ 1 -eq 1 ]]; then
    echo hoge
fi

# 複合コマンド(算術式)
if ((1==1)); then
    echo hoge
fi

for文のフレンズ

for文のフレンズ
# 直書きリストのイテレーション
for x in aaa bbb ccc; do
    echo "$x"
done

# 変数に格納された値をイテレーション
xs="aaa bbb ccc"
for x in $xs; do
    echo "$x"
done

# GLOB展開の結果をイテレーション
for x in *.log; do
    echo "$x"
done

# コマンド置換の結果を単語単位でイテレーション
for x in $(command); do
    echo "$x"
done

# ファイルを単語単位でイテレーション(コマンド置換)
for x in $(cat sample.log); do
    echo "$x"
done

# ファイルを単語単位でイテレーション(コマンド置換(上より高速))
for x in $(<sample.log); do
    echo "$x"
done

# 整数のイテレーション(ブレース展開)
for x in {1..10}; do
    echo "$x"
done

# 整数のイテレーション(seqコマンド)
for x in $(seq 1 10); do
    echo "$x"
done

# C言語風のイテレーション
for((i=0; i<10; ++i)); do
    echo "$i"
done

# 配列のイテレーション
xs=("aaa" "bbb" "ccc")
for x in "${xs[@]}"; do
    echo "$x"
done 

while文のフレンズ

while文のフレンズ
# 無限ループ
while true; do
    echo hoge
done

# ファイル行単位のイテレーション(パイプライン)
cat sample.log | while read line; do
    echo "$line"
done

# ファイル行単位のイテレーション(リダイレクト)
while read line; do
    echo "$line"
done <sample.log

# ファイル行単位のイテレーション(プロセス置換)
while read line; do
    echo "$line"
done < <(cat sample.log)

ワンライナーのフレンズたち

ふつうのフレンズたちを、すべてワンライナーにしてみました。

ワンライナーのフレンズたち
# if文ワンライナーのフレンズ
if true; then echo "$x"; fi
if [ 1 -eq 1 ]; then echo hoge; fi
if [[ 1 -eq 1 ]]; then echo hoge; fi
if ((1==1)); then echo hoge; fi

# for文ワンライナーのフレンズ
for x in aaa bbb ccc; do echo "$x"; done
for x in $xs; do echo "$x"; done
for x in *.log; do echo "$x"; done
for x in $(cat sample.log); do echo "$x"; done
for x in $(<sample.log); do echo "$x"; done
for x in {1..10}; do echo "$x"; done
for x in $(seq 1 10); do echo "$x"; done
for((i=0; i<10; ++i)); do echo "$i"; done
for x in "${xs[@]}"; do echo "$x"; done 

# while文ワンライナーのフレンズ
while true; do echo hoge; done
cat sample.log | while read line; do echo "$line"; done
while read line; do echo "$line"; done <sample.log
while read line; do echo "$line"; done < <(cat sample.log)

おまけのフレンズたち

最終行の末尾改行の有無によって、イテレーションの結果が変わる

(このフレンズは「bashで意外だったこと、普段気になってるアレは何なんだ?を記録するノート」より転載したものです)

複数行のデータを読み込んでwhile等でイテレーションする際、最終行の末尾に改行文字が存在しない場合、最終行が無視されてしまいます。

$ printf "aaa\nbbb\nccc" | while read line; do echo $line; done
aaa
bbb
$ printf "aaa\nbbb\nccc\n" | while read line; do echo $line; done
aaa
bbb
ccc
$ while read line; do echo $line; done < <(printf "aaa\nbbb\nccc")
aaa
bbb
$ while read line; do echo $line; done < <(printf "aaa\nbbb\nccc\n")
aaa
bbb
ccc

最終行末尾に改行のないファイルをcatしてパイプにつなげてテキスト処理する場合など、大変危険。

if true; then ~; fi

if文の条件部にtruefalseを書く場合、以下のように書くのが正しいです。

○正しい
if true; then
    echo hoge
fi
if false; then
    echo hoge
fi

以下のように書くと「文字列"true""false")の長さは1以上である」という条件になってしまうため、恒真条件になります。[[ string ]]は、[[ -n string ]]と同じ意味になるためです。

×誤り
if [ true ]; then
    echo hoge
fi
if [[ false ]]; then
    echo hoge
fi

複合コマンドの条件部に複合コマンドを書く

条件部にはリストを書けるため、if文や複合コマンドを書くこともできます。

while if true; then echo hoge; fi; do
    echo fuga
done

だから何だ!

for x; do ~; done

for文は、以下のような書き方も可能です(in $xsの部分がない!)

for x; do
    echo "$x";
done

この場合、位置パラメータ$1$Nをイテレーションします。

$ bash -c 'for x; do echo "$x"; done' -s aaa bbb ccc
aaa
bbb
ccc
$ f(){ for x; do echo "$x"; done;}
$ f aaa bbb ccc
aaa
bbb
ccc
$ set +f; set -- aaa bbb ccc; set -f
$ for x; do echo "$x"; done
aaa
bbb
ccc

for文のC言語風のイテレーションについて

@akinomyogaさんより頂きましたコメントにあります、for((;;)); dodoの直前のセミコロンの省略についてです。

以下のfor文ですが、

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

僕の環境では、これの++i)); doのセミコロン;をつけずに以下のように書いても正常動作しました。

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

また、ループ本体を{}で括って、以下のように書いても正常動作しました(むしろ、こちらの方が有名ですよね)。

for((i=0; i<10; ++i)){
    echo "$i"
}

C言語風のforループに関しては記法がゆるやかなんだなあ…と思い、念のためman bashを確認したところ、for((;;)); do :; done形式の記法しか記載が無いではないですか。

man_bash「Compound Commands」より抜粋
for name [ [ in [ word ... ] ] ; ] do list ; done
    The list of words following in is expanded, generating a list of items.  The variable name is set to  each  element  of  this
    list  in  turn, and list is executed each time.  If the in word is omitted, the for command executes list once for each posi‐
    tional parameter that is set (see PARAMETERS below).  The return status is the exit status of the last command that executes.
    If the expansion of the items following in results in an empty list, no commands are executed, and the return status is 0.

for (( expr1 ; expr2 ; expr3 )) ; do list ; done
    First,  the arithmetic expression expr1 is evaluated according to the rules described below under ARITHMETIC EVALUATION.  The
    arithmetic expression expr2 is then evaluated repeatedly until it evaluates to zero.  Each time expr2 evaluates to a non-zero
    value,  list is executed and the arithmetic expression expr3 is evaluated.  If any expression is omitted, it behaves as if it
    evaluates to 1.  The return value is the exit status of the last command in list that is executed, or false  if  any  of  the
    expressions is invalid.

というわけなので、僕はマニュアルに従ってfor((;;)); do :; done形式で書くようにしたいと思います(@akinomyogaさんのコメント以後、本記事当該箇所のfor文にも念のため;をつける修正をしました)。

なお、上記のマニュアルの抜粋にもある通り、in句の無いfor文に関してはdo直前のセミコロンは必須ではないようです。

$ bash -c 'for x do echo "$x"; done' -s aaa bbb ccc
aaa
bbb
ccc
$ bash -c 'for x; do echo "$x"; done' -s aaa bbb ccc
aaa
bbb
ccc
18
27
2

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
18
27