シェルスクリプトに挑戦しよう(11)制御構文[その3]――forによる繰り返し処理(1)“応用力”をつけるためのLinux再入門(31)

繰り返し処理では、「for文」または「while文」を使用します。今回は、「for」による繰り返し処理を解説します。for文では、“カレントディレクトリのファイルを順次処理する”のようにリストを基に繰り返す処理や、“1から10まで”のように回数を基にした繰り返し処理を行います。

» 2018年12月19日 05時00分 公開
[西村めぐみ@IT]
「“応用力”をつけるためのLinux再入門」のインデックス

“応用力”をつけるためのLinux再入門

forの基礎構文(1)――リストの処理

 「for 変数 in リスト do 〜 done」で、リストを一つ一つ変数にセットして、doからdoneの間に書かれた処理を実行します。

for 変数 in リスト
do
  コマンド
done
▲リストを使って繰り返すfor文の書き方

 forはコマンドラインで使用することもできます。筆者の別連載「Linux基本コマンドTips」の第215回も参考にしてください。

●for文を試してみる

 for文の雰囲気をつかむために、「1」「2」「3」と順番に表示するスクリプトを作ってみましょう。

#! /bin/bash
for cnt in 1 2 3	#1,2,3を順番にcntにセットしてdo〜doneを処理する
do
  echo $cnt		#変数cntの内容を表示する
done
▲数字を1つずつ表示する(showcount)
$ chmod +x showcount
$ ./showcount
1
2
3
▲実行結果(showcount)

 少し応用すると、以下のような実行も可能です。以下のスクリプトでは、do〜doneの中で「echo」コマンドと「ping」コマンドを実行しています。

#! /bin/bash
for cnt in {1..5}	#1,2,3,4,5を順番にcntにセットしてdo〜doneを処理する
do
  echo "check: 192.168.1.$cnt"
  ping -c 3 192.168.1.$cnt	#pingを実行(「-c 3」は3回トライして終了するオプション)
done
▲数字を1つずつ表示する(seqping)
$ chmod +x seqping
$ ./seqping
check: 192.168.1.1		← echoコマンド
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.	← pingコマンド
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.974 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.787 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=0.788 ms
--- 192.168.1.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
rtt min/avg/max/mdev = 0.787/0.849/0.974/0.094 ms
check: 192.168.1.2		← echoコマンド
PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.	← pingコマンド
…
#(192.168.1.1〜192.168.1.5に対しechoとpingが実行される)
▲実行結果(seqping)

●for文の改行ルール

 for文では、doの前とdoneの前に“改行“が必要です。また、if文と同様に「;」記号で改行をなくすことができます。

 先ほどの「showcount」スクリプトを書き換えると、以下のようになります。どちらも内容は全く同じです。

#! /bin/bash
for cnt in 1 2 3; do
  echo $cnt
done
▲「;」記号でdoの前の改行をなくす(showcountを加工)
#! /bin/bash
for cnt in 1 2 3; do echo $cnt; done
▲for文を1行で書く(showcountを加工)

引数を順番に処理するスクリプト

 次に“引数を1つずつ表示する”というスクリプトを作ってみましょう。ここでは「for argv in $@」のように指定しています。

 「$@」はシェルスクリプト実行時の「全ての引数」という意味で、例えば「showargv one two three」と実行した場合は、「one」「two」「three」を順番に変数argvに入れて、doとdoneの間の処理を実行します。

#! /bin/bash
for argv in $@		#引数を1つずつ変数argvに入れて「do〜done」の間を実行する
do
  echo $argv			#変数argvの内容を表示する
done
▲引数を1つずつ表示する(showargv)
$ chmod +x showargv
$ ./showargv one two three
one
two
three
#(引数が1つずつ表示された)
▲実行結果(showargv)

ファイルを順番に処理するスクリプト

 先ほどのshowargvは、コマンドラインで「showargv *」のように実行すると、カレントディレクトリにあるファイルが1つずつ表示されることになります。これは、bashによって「*」部分がカレントディレクトリにある全てのファイル名に展開された上で実行されているためです。これを「パス名展開(Pathname Expansion)」と呼びます。

 例えば、カレントディレクトリに「file1」「file2」「file3」があったならば、「showargv *」で「showargv file1 file2 file3」が実行されます。

$ ls *
file1   file2   file3
#(カレントディレクトリにfile1、file2、file3がある)
$ showargv *
file1
file2
file3
#(パス名展開されてshowargv file1 file2 file3が実行された)
▲実行結果(showargv)

 以上を踏まえて、“指定したファイルを「ファイル名.年-月-日」にコピーする”という想定でスクリプトを作ってみましょう。

 先ほどと同じ要領で「for f in "$@"」で引数を1つずつ変数fにセットし、「cp」コマンドでファイルをコピーします。ファイル名は、元のファイル名に対し「.」という文字と、「date +%Y-%m-%d」の実行結果を追加しています。

 なお、今の段階では、cpコマンドの前に「echo」を付けています。「このようなコマンドが実行されるはず」というイメージで実行結果を参照してください。

#! /bin/bash
for filename in "$@"
do
  echo cp "$filename" "$filename.`date +%Y-%m-%d`"
done
▲引数で指定したファイルを「ファイル名.年-月-日」にコピーする(filebackup)
$ filebackup *			##引数に「*」を指定
cp file1 file1.2018-12-11
cp file2 file2.2018-12-11
cp file3 file3.2018-12-11
#(このようなcpコマンドが実行される予定)
▲想定する実行結果1(filebackup)(※実行結果はカレントディレクトリに存在するファイルに応じて変化します)
$ filebackup file1 file2	#ファイル名を個別に指定してもよい
cp file1 file1.2018-12-11
cp file2 file2.2018-12-11
#(このようなcpコマンドが実行される予定)
▲想定する実行結果2(filebackup)(※実行結果はカレントディレクトリに存在するファイルに応じて変化します)

 filebackupスクリプトの「echo cp 〜」部分からechoコマンドを取って「cp 〜」のようにすると、cpコマンドが実行されます。

 次回は、この「filebackup」スクリプトを加工して、ファイルのコピーと圧縮を行うスクリプトを作成します。また、引数で指定したファイルの有無を確認したり、指定したファイル名の中に空白があったりした場合の対策も行います。

筆者紹介

西村 めぐみ(にしむら めぐみ)

もともとはDOSユーザーで「DOS版UNIX-like tools」を愛用。ソフトハウスに勤務し生産管理のパッケージソフトウェアの開発およびサポート業務を担当、その後ライターになる。著書に『図解でわかるLinux』『らぶらぶLinuxシリーズ』『Accessではじめるデータベース超入門[改訂2版]』『macOSコマンド入門』など。地方自治体の在宅就業支援事業にてMicrosoft Officeの教材作成およびeラーニング指導を担当。会社などの“PCヘルパー”やピンポイント研修なども行っている。


Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。