シェルスクリプト練習問題(入門編)の正解例と解説

こちらのシェルスクリプト練習問題(入門編)の正解例と解説をします。
http://g-network.boo.jp/wiki/2018/02/post-879/
 
シェル名 shell_nyumon_01.sh
処理内容 echoコマンドで「Hello   World」と表示させる。
※あいだに半角3文字分のスペースをいれること
 
【正解例】
 
【解説】
ダブルクォートやシングルクォートでくくらないと、echoコマンドにHelloとWorldという2つの引数を与えて実行になってしまう。ダブルクォートとシングルクォートの違いはこちらを参照。https://qiita.com/cocodrips/items/bb3640a9834c8978d48a
今回の場合はダブルクォートでもシングルクォートでも同じ結果が得られる。
またファイルのパーミッションに実行権限がついていないとシェルを実行できない。その場合はchmodコマンドで実行権限を付与する必要がある。viの操作には早めに慣れておいた方がよい。
 
シェル名 shell_nyumon_02.sh
処理内容 以下2つのlsコマンド(正常終了するパターンとエラー終了するパターン)をシェルで実行させ、両方の結果をshell_02.tmpに出力させること
ls -l
ls -l aaa
 
【正解例】
 
【解説】
コマンド結果の出力は標準出力である1とエラー出力の2に分類される。単純に「 > shell_02.tmp」とすれば一見良さそうに見えるが、実はこれは「1> shell_02.tmp」の1が省略された形である。つまりこれだと標準出力の1をファイルに出力させるという意味で、コマンドがエラーだった際(エラー出力の2)はデフォルトの出力先である画面に出力されてしまう。両方ともファイルに出力させる時は以下のように記載する。結果はどれも同じだが1番上の書き方をしている現場が多い気がする。
 
ls -l test > shell_02.tmp 2>&1
ls -l test &> shell_02.tmp
ls -l test >& shell_02.tmp
ls -l test 1> shell_02.tmp 2>> shell_02.tmp
 
ちなみに用途としてコマンドの戻り値だけを取得して処理したい時などに使う場合が多く、その場合「> /dev/null 2>&1」という風に/dev/nullにリダイレクトして何も出力させないようにする。
 
シェル名 shell_nyumon_03.sh
処理内容 実行日の日付(YYYYMMDDの形式)をコマンドで取得していったん変数DATEに代入し、その変数の値を表示する

 
【正解例】

 
【解説】
シェルの場合、他の言語のように変数の宣言は不要。特にしなくてはいけないわけではないが、見やすくするために変数名は大文字にする場合が多い。また変数名の頭を数字にすることはできない。

そして変数にコマンド結果を代入するには以下のやり方がある。

  ① 変数名=$(コマンド)
  ② 変数名=`コマンド`
 
上記の記号はバッククォートでありシングルクォートではないので注意。どちらの方法を使うかは現場のコーディング規約にもよりますが、自分の経験だとそれぞれの使用頻度は半々くらいな気がします。どちらの使い方も覚えておくのと、どんな違いがあるかは理解しておいたほうがよいです。
 
また変数は基本的に { } でくくったほうがよい。くくっていないと変数の直後に文字列が来た時にちゃんと動かない。
 
DATE=20180220
echo $DATElog
 
※20180220logと表示させたいが、DATElogという変数名として認識してしまうためうまくいかない。こういう時は、echo ${DATE}logとすればうまくいく。なので初めから変数には {}
をつけることで統一しておいたほうが分かりやすい。
 
dateコマンドの出力形式は色々あるので場合に応じて使い分けられます。現場で1番よく使うのはYYYYMMDDの形で出力させる上述の正解例の形式が多いです。
 
 
シェル名 shell_nyumon_04.sh
処理内容 シェルを実行した際に、引数付きで実行すると「引数あり」、引数なしで実行すると「引数なし」と表示されるようにする。またデバッグモードでもシェルを実行してみる

 
【正解例】

 
【解説】
変数には特殊変数といって、決められた情報が自動的に格納される変数がある。$#はシェル実行時の引数の個数を表す特殊変数。この値をif文で判定して分岐させればよい。他の特殊変数も使用頻度は高めなので覚えておいたほうがよい。
 
if文のthenを書く場所は2行目ではなく、1行目の後ろに書くルールにしている現場のほうが多い気がする。
 
またデバッグモードで実行することで、変数が実際にどんな値に置き換わりコマンドが実行されたかが分かるので、処理が思い通りにいかない時はとりあえずデバッグモードで実行して原因を探ることができる。
 
デバッグモードで実行するには以下のように-xを使う。
/bin/sh -x ./shell_04.sh
 
もしくはシェル内の1行目に-xをつけた状態で普通にシェルを実行する
#!/bin/sh -x
 
 
シェル名 shell_nyumon_05.sh
処理内容 ファイルのフルパスを引数で指定して、ファイルが存在したら「ファイルあり」と出力させ、存在しなかったら「ファイルなし」と出力させる
 
【正解例】

 
【解説】

if文(testコマンド)の条件式の書き方について以下は覚えておくべき
・文字列の比較
・数値の比較
・その他のオプション指定(特に-f、-d、-zあたり)
・NOT条件
・AND条件、OR条件
 
また$1は引数の1つ目が代入される特殊変数。
 
 

シェル名 shell_nyumon_06.sh
処理内容 ファイルのパスを引数で指定して、そのファイルをlsして戻り値が0ならばls結果を表示して終了コード0で終了、戻り値が0以外だったら「エラー終了」と表示し、終了コード1で終了させる。

 

【正解例】
 
【解説】
コマンドの終了コードは特殊変数の$?で確認できる。$?は直前のコマンドの終了コードが格納され、正常終了ならば0を返し、エラーならばそれ以外の値になる。
 
ls -l $1 > /dev/null 2>&1
この行は問題②で説明した通り、コマンド結果を全て/dev/nullに捨てて画面に何も表示しないようにしている。次のif文で$?を使ってlsコマンドの終了コードを得るためだけに実行している。
 
$?は直前のコマンドの終了コードしか確認できないため、確認したいコマンドの後に別のコマンドをはさんでしまうと、そちらの終了コードが表示されてしまうので注意。
 
またシェルスクリプトにおいては、作る側で正常終了の時は終了コードを0に、エラーの時はそれ以外になるようにコーディングするのが普通である。やり方はexitの後に終了コードに指定したい数字を記載するだけでよい。
 
シェルを実行後にプロンプト上でecho $?を実行すると、シェルの終了コードが確認できる。
 
ちなみに、リターンコード、戻り値、終了ステータスなどは、呼び名が違うだけで全て終了コードと同じ意味です。
 
 

シェル名 shell_nyumon_07.sh
処理内容 引数に1か2かそれ以外を与えてシェルを実行した際に、それぞれ以下のような処理をすること
引数が1 → 「引数は1です」と表示
引数が2 → 「引数は2です」と表示
引数がそれ以外 → 「正しい引数を入力してください」を表示
※case文を使うこと
 
【正解例】
 
【解説】
case文の書き方を覚えること。パターンのところ(「 1) 」や「 2) 」や「 *) 」の部分)はワイルドカードも使用することができる。
 
 ;; を忘れやすいので気をつけること。基本的にif文でも同じ処理はできるが、aかbかcという風に3ケース以上の分岐になる場合や、if文より見やすくなる時はcase文を使った方がよい。
 
 

シェル名 shell_nyumon_08.sh
処理内容 引数に文字列を1つ以上与えて、ループ処理で全ての引数の文字列をechoで表示させる
※for文を使うこと

 
【正解例】

 
【解説】
for文の書き方を覚えること。特殊変数の$@は全引数を表すため、上記のようにすると引数の個数分だけループしてechoコマンドを実行することができる。
 
 
シェル名 shell_nyumon_09.sh
処理内容 while文で3回ループさせて以下のように出力させる
(出力結果)
1回目
2回目
3回目 
 
【正解例】
 
【解説】
while文の書き方を覚える。while文は条件を満たしている間はループし続けるため、今回の場合は以下の部分で変数NUMをループごとに1ずつ足していくことでループから抜け出します。
  NUM=`expr ${NUM} + 1` 
 
この変数を1増やす演算のことをインクリメントといいます。
 
while文は条件式の不等号の向きを間違えたりすると、無限ループに陥ったりするので注意が必要です。
 
 
シェル名 shell_nyumon_10.sh
処理内容 while文を無限ループで実行し、3秒おきにdateコマンドを実行させる
 
【正解例】
 
【解説】
while文でわざと無限ループさせる時は、条件式に: (ヌルコマンド)を書くだけでよい。ちなみに: の代わりにtrueと書いても同じ意味となる。
 
またsleepコマンドを使うことで指定した秒数だけ待機してくれる。上記のスクリプトで、もしsleepコマンドがないとものすごいスピードで無限ループしてdateコマンドの結果を出力してしまいます。
 
 
次は練習問題(初級編)にチャレンジ!!
スポンサーリンク
勉強wikiの下部広告
  • このエントリーをはてなブックマークに追加
スポンサーリンク
勉強wikiの下部広告

コメントをどうぞ

メールアドレスが公開されることはありません。

CAPTCHA