tanke25616429のアウトプット

IT技術の基本を勉強したことをアウトプットします。Linux、Kubernetes、クラウド中心です。百番煎じくらいだけど誰かの役に立てばそれはそれでうれしい。

bashの制御構文(for文、if文)

この記事の目的

シェルスクリプトで自分がいろいろ混乱しがちな制御構文の備忘録として記す。種類はbashシェルとする。

事前準備

いろいろ試す用のシェルスクリプトのファイルを作成する*1

[testuser@nuc-centos8 shelltest]$ touch test.sh
[testuser@nuc-centos8 shelltest]$ chmod +x test.sh
[testuser@nuc-centos8 shelltest]$ cat > test.sh
#!/bin/sh
echo hogehoge
[testuser@nuc-centos8 shelltest]$ ./test.sh
hogehoge

サンプルのファイルも置いておく。

[testuser@nuc-centos8 shelltest]$ ls
fileA  fileB  fileC  test.sh

制御構文

for文

for 変数 in 変数の取りうる値の列挙; do
 処理
done

の形式になる。処理をdo~doneではさむこと、doの前にセミコロン;が入ることがポイント。以下が実例。

#!/bin/sh

for file in fileA fileB; do
        ls -i $file
done
[testuser@nuc-centos8 shelltest]$ ./test.sh
144 fileA
145 fileB

列挙の部分は何らかのコマンドの実行結果にしてもよい。コマンドの実行結果を展開するので` `で実行したいコマンドを囲う。

#!/bin/sh

for file in `ls`; do
        ls -i $file
done
[testuser@nuc-centos8 shelltest]$ ./test.sh
144 fileA
145 fileB
146 fileC
147 test.sh

シェルスクリプト内のセミコロンはシェル上のワンライナーで書く場合は、処理の後にもつける。

[testuser@nuc-centos8 shelltest]$ for file in `ls`; do ls -i $file; done
144 fileA
145 fileB
146 fileC
147 test.sh

if文

if [ 条件 ]
then
 処理
elif [ 条件 ]
then
 処理
else
 処理
fi

の形式となる。if~fiで囲むこと、ifとelifの後はthenが入るが最後のelseの後は入らないこと、[ ](ブレース)の条件と左右の括弧の間は半角スペースが必要なことなどがポイントである。

#!/bin/sh

if [ $1 -lt 3 ]
then
        echo AAA
elif [ $1 -eq 3 ]
then
        echo BBB
else
        echo CCC
fi
[testuser@nuc-centos8 shelltest]$ ./test.sh 5
CCC
[testuser@nuc-centos8 shelltest]$ ./test.sh 3
BBB
[testuser@nuc-centos8 shelltest]$ ./test.sh 2
AAA

[ ]thenを同一行に書くこともできるが、その場合は;で区切る必要がある。ワンライナーで書いてみる。ワンライナーで書く場合は処理部分の最後にも;が必要。

[testuser@nuc-centos8 shelltest]$ if [ `ls | wc -w` -eq 4 ]; then echo Yes; fi
Yes

ファイルのタイプを確認できるtestコマンドがあるが、if文の[ ]の中身はtestコマンドと同じである。

[testuser@nuc-centos8 shelltest]$ mkdir dir
[testuser@nuc-centos8 shelltest]$ ln -s /etc/
[testuser@nuc-centos8 shelltest]$ ls -l
total 4
drwxrwxr-x. 2 testuser testuser  6 Mar 19 01:23 dir
lrwxrwxrwx. 1 testuser testuser  5 Mar 19 01:23 etc -> /etc/
-rw-rw-r--. 1 testuser testuser  0 Mar 19 00:31 fileA
-rw-rw-r--. 1 testuser testuser  0 Mar 19 00:31 fileB
-rw-rw-r--. 1 testuser testuser  0 Mar 19 00:31 fileC
-rwxrwxr-x. 1 testuser testuser 93 Mar 19 01:07 test.sh

-fで通常ファイルかどうかを確認する。$?は直前のコマンドの終了ステータスで0は成功、1は失敗である。fileAは通常ファイルだが、dirはディレクトリなので以下のような結果になる。

[testuser@nuc-centos8 shelltest]$ test -f fileA; echo $?
0
[testuser@nuc-centos8 shelltest]$ test -f dir; echo $?
1
[testuser@nuc-centos8 shelltest]$ if [ -f fileA ]; then echo Yes; fi
Yes
[testuser@nuc-centos8 shelltest]$ if [ -f dir ]; then echo Yes; fi
[testuser@nuc-centos8 shelltest]$

-dで通常ファイルかどうかを確認する。dirはディレクトリだが、filrBは通常ファイルでディレクトリではないので以下のような結果になる。

[testuser@nuc-centos8 shelltest]$ test -d dir; echo $?
0
[testuser@nuc-centos8 shelltest]$ test -d fileB; echo $?
1
[testuser@nuc-centos8 shelltest]$ if [ -d dir ]; then echo Yes; fi
Yes
[testuser@nuc-centos8 shelltest]$ if [ -d fileB ]; then echo Yes; fi
[testuser@nuc-centos8 shelltest]$

-Lシンボリックリンクかどうかを確認する。etcはシンボリックリンクだがdirはそうではないので以下のようになる。

[testuser@nuc-centos8 shelltest]$ test -L etc; echo $?
0
[testuser@nuc-centos8 shelltest]$ test -L dir; echo $?
1
[testuser@nuc-centos8 shelltest]$ if [ -L etc ]; then echo Yes; fi
Yes
[testuser@nuc-centos8 shelltest]$ if [ -L dir ]; then echo Yes; fi
[testuser@nuc-centos8 shelltest]$

参考にしたもの

qiita.com

qiita.com

www.koikikukan.com

【 expr 】コマンド――計算式や論理式を評価する:Linux基本コマンドTips(171) - @IT

stackoverflow.com

www.atmarkit.co.jp testコマンド、条件分岐

*1:ちなみにスクリプトの冒頭にある#!から始まる1行目をシェバン (shebang)と呼ぶ。起動して読み込むインタプリタ(シェルの種類など)を指定する。shを指定しているが、この環境ではbashエイリアスになっている。