前回まではUNIX系シェル(bash,zsh)でファイル内容の置き換えをしました。今回はWindows系シェルのPowerShellを使ってファイル内容の置き換え処理を行ってみます。
PowerShellは本家Windows以外にもありますが、環境によって動作するコマンドが異なる場合があります。ここでは、これまで通りのWindowsとMac版のPowerShellで説明します。
と、その前に前回のbash,zshでの続きからです。前回はシェルを使って渡されたパラメーターに応じて処理を行いました。今回は少し便利かもしれない機能を説明します。なお、今回もサンプルファイルとシェルスクリプトはデスクトップ上に用意したsampleフォルダ内にあるものとします。cd ~/Desktop/sampleとコマンドを入力してカレントディレクトリを変更しておきましょう。
パラメーターを指定し忘れた場合の処理
シェルからコマンドや文字を入力するのは人間です。人間は必ず間違えます。前回のシェルスクリプトでも、パラメーターを指定し忘れてしまう、もしくは素早く入力しすぎてパラメーターを入れる前にリターンキーを押してしまった!?みたいな事もあります。
こういうミスはプログラム側でカバーする必要があります。人間側が気をつけるべきだ、という意見もあるかもしれませんが、それは実際のところ良い対処方法ではありません。
今は昔と違いメモリなど使えるリソースが豊富ですから、可能な限りミスをした場合の処理を入れておくのがよいと思います。自分は絶対にミスしないという人は、エラー処理を入れなくても構いません。その方がプログラムに取っては、分かりやすく見通しがよくなるというメリットもあるからです。
今回はパラメーターを指定し忘れた場合のみ対処してみましょう。まず、パラメーターを指定し忘れているというのを、どのように判断すればよいのか?ということです。
パラメーターをまったく指定していないという事はパラメーターの数がゼロだという事になります。都合のいいことにシェルには渡されたパラメーターの個数を保持している変数$#があります。
それでは実際にテストしてみましょう。以下のようにシェルスクリプトを作成し保存します。ファイル名はtest6.shとし実行権限を付けます。
#!/bin/bash
echo $#
./test6.shと入力して実行します。何もパラメーターを指定していないので画面には0が表示されます。
それでは次に./test6.sh 2021と入力して実行してみてください。今度はパラメーターが1つだけ指定されているので1が表示されます。
今度はパラメーターを変えて実行してみてください。指定したパラメーターの数が表示されるはずです。
パラメーターの数がわかれば、あとは指定し忘れた場合の処理を書くだけです。
ifによる条件分岐
パラメーターの数に応じて条件を分けるにはifを使います。ifはシェルスクリプトに限らず、多くのプログラム言語でも使われる条件判断命令・文です。bash,zshなどのシェルでは以下の書式で条件分岐処理を書きます。
if 条件や処理
then
条件成立時の処理
fi
ただし、読みやすさ(可読性)の都合でthenはifと同じ行に書かれることが多く、ここでも以下の書式を使うことにします。シェルでは複数行を1行で記述する場合は;(セミコロン)を使います。thenも御多分にもれず以下のようになります。
if 条件や処理 ;then
条件成立時の処理
fi
ところでifはわかるけどfiって何だ?と思う人もいるかもしれません。これは単純にifのスペル(英文のつづり)を逆にしただけです。シェルでは、このfiがあると、そこでifに関する処理を終了します。メジャーなプログラム言語(C言語のようなアルゴル系言語。Java言語なども)ではifの条件判断は{ }のブロックを示す記号で書かれますがシェルでは、この記号は他の用途に使用していますので使えません。基本的にシェルはメモリが少ない時代に作成されているので、今の時代には何で?と思うような謎ルールになってしまう面もあります。興味ある方は8KBくらいのメモリサイズでシェルのようなものを作ってみると良いかもしれません。
話がそれたので本題に戻りましょう。パラメーターの数が0だったらメッセージを表示して終了するという処理を追加してみます。
ところでメッセージを表示してシェルスクリプトでの処理を終了するには、どうしたらよいのでしょうか。シェルスクリプトを終了させるにはexitを使います。その際、exitの後に終了ステータスを数値(0〜255)で指定します。0なら正常終了で0以外ならエラーということになります。この終了ステータスはifで使うだけでなく、コマンドの連続実行にも役立ちます。
今回のシェルスクリプトではパラメーターが指定されていなかったらエラーステータス1で終了することにします。どんなエラーの値にするかは作成者に一任されています。
実際のシェルスクリプトは以下のようになります。まだ説明していない部分もありますが、とりあえずtest7.shという名前で保存し実行権限を付けましょう。
#!/bin/bash
if [ $# -eq 0 ]; then
echo "パラメーターを指定してください"
exit 1
fi
./test7.shと入力して実行します。するとパラメーターが足りないのでエラーメッセージが表示され終了します。
今度は./test7.sh MyNaviと入力して実行します。今度はパラメーターが指定されているためエラーメッセージは表示されません。
ただ、何も表示されないので本当に正常終了したのか分かりません。そんな時は終了ステータスを表示すればOKです。終了ステータスは最後に実行したコマンドの内容を示す変数$?に格納されています。echoコマンドを使えば値を表示できます。
echo $?
ifで指定できる条件
ifで説明していない部分がありました。それがifの後に指定できる条件です。今回のようなパラメーターの数値の比較では以下の条件を指定できます。
-eq | 等しい |
---|---|
-ne | 等しくない |
-lt | 小さい |
-le | 等しいか小さい |
-gt | 大きい |
-ge | 等しいか大きい |
条件を書くときに注意しないといけない点があります。ifの後に[を書きますが、半角空白を入れずにif[とすると動きません。ifの後に半角空白がないといけません。これに限らず条件で書く-eqや変数の前後、]の前にも半角空白が必要です。半角空白が区切りとして使われるので動かない場合は確認してみてください。
数値でなく文字列の判断もできます。文字列の場合は以下の条件を指定できます。
= | 等しい |
---|---|
!= | 等しくない |
例えばシェルスクリプトに渡された最初のパラメーターがabcかどうかチェックするには以下のようになります。
#!/bin/bash
if [ "$1" = "abc" ]; then
echo "パラメーターはabcでした"
fi
渡されたパラメーターは$1,$2のように参照できますが、ifの条件式では"〜"で囲む必要があります。これにより変数が評価され内容と比較できるようになります。ちなみに"abc"としていますが、文字列内に変数を含まない、純粋に文字列だけなら以下のように'〜'で囲むのがよいでしょう。
#!/bin/bash
if [ "$1" = 'abc' ]; then
echo "パラメーターはabcでした"
fi
他にも条件で使えるものがありますが、とりあえず数値と文字列のチェックができれば用途としては十分です。
これで、ようやくエラー処理を組み込んだシェルスクリプトを作ることができます。完成したシェルスクリプトは以下のようになります。
#!/bin/bash
if [ $# -eq 0 ]; then
echo "パラメーターを指定してください"
exit 1
fi
sed s/INFO/$1/ infotemp.txt > info.txt
infotemp.txtの内容
ようこそ喫茶マイナビへ。さまざまなレトロUNIXマシンを用意して、お待ちしております。
INFO
Tel:00-0000-0000
url:myna-bee.shop
おまけTIPS
ちなみにもっと短くシンプルにしたい場合は&&を使って以下のように書く方法もあります。渡されたパラメーターが1つだけの場合に&&以後の処理を実行します。
#!/bin/bash
[ $# -eq 1 ] && sed s/INFO/$1/ infotemp.txt > info.txt
パラメーターが指定されていない場合には、あらかじめ決められた値にする方法があります。つまりデフォルトパラメーターというやつです。変数に何も入っていない場合に数値や文字列を入れるには${変数名-文字列}のように指定します。ちょっとテストしてみましょう。以下のようにシェルスクリプトを用意します。ここではtest12.shという名前で保存し実行権限を付けました。
#!/bin/bash
echo ${1-'営業中'}
パラメーターを指定して実行すると、渡されたパラメーターが表示されます。
今度はパラメーターを指定せずに実行すると営業中の文字が表示されます。つまり、デフォルトのパラメーターで処理されたことになります。
これを利用すると以下のように短く書くことができます。パラメーターを指定した場合と、そうでない場合の処理を比較すると期待通りの結果になっていることがわかります。
#!/bin/bash
sed s/INFO/${1-'営業中'}/ infotemp.txt > info.txt