助け合いフォーラム

Essentials

Linux Essentials(Ver1.6)
問題ID : 2833
問題を開く
シェルスクリプト「test.sh」は以下の内容である。
 #!/bin/bash
 echo $TEST

次のコマンドを実行したとき、正しい結果はどれか。なお、スクリプト「test.sh」には実行権が与えられているものとする。
 $ TEST="test"
 $ ./test.sh

正解

何も出力されない

解説

シェル変数の扱いは、シェルスクリプトの実行の仕方で異なります。

・sourceコマンド ... 指定したシェルスクリプトを読み込み、現在のシェルで実行する。スクリプトで設定した変数はシェル変数として現在のシェルで参照される。また、現在のシェルに設定しているシェル変数もスクリプトで参照される
・bashコマンド ... シェルを起動してシェルスクリプトを実行する。スクリプトで設定した変数はスクリプト内(起動したシェル内)で完結し、現在のシェルに設定しているシェル変数もスクリプトへ反映されない

なお、実行権のついたスクリプトを「./test.sh」などと実行した場合はbashコマンドでの実行結果と同じです。

したがって、本例ではスクリプトを実行する直前にシェル変数TESTへ値を代入していますが、この値はシェルスクリプトへは反映されません。

以上より正解は
・何も出力されない
です。

スクリプトへシェル変数TESTの値を反映させるには以下の二通りがあります。
・sourceコマンドでスクリプトを実行する(source test.sh)
・シェル変数TESTを環境変数にする(export TEST)

例)コマンドの実行方法におけるシェル変数の扱い


例)コマンドの実行方法における環境変数の扱い


その他の選択肢は誤りです。

参考

【スクリプト】
GUI(Graphical User Interface)と比べた時のCUI(Character User Interface)の利点に、一連の手続きをファイルに保存し、自動化できる「スクリプト」があります。
スクリプト(script:台本、脚本など)とは、プログラムのように「人間がコードを書く」→「機械語へ翻訳する」→「実行」という段階を経ることなく、人間が書いたコードをそのまま実行することができます。
LinuxにはcshやBashなどのシェルがありますが、シェルに読み込ませるスクリプトを「シェルスクリプト」といいます。本項ではBashの構文を基に、スクリプトについて学習します。

●簡単なスクリプト
シェルスクリプトは、今までに覚えたコマンドを利用して作ることができます。
例えば、「ホームディレクトリへ移動し、ファイル一覧を表示する」というだけの一連の手続きをスクリプトにすると以下のようになります。

 #!/bin/bash
 cd ~/
 ls

この3行をファイル「home.sh」として保存し、「bash home.sh」と実行すると、記述した通りに実行されます。
シェルスクリプトでは、このような簡易なものだけでなく、複雑な処理も行うことができます。

【基本的な構文】
●シェバン(shebang)
先例「home.sh」の1行目は、Bashでスクリプトを実行する、という意味のおまじないで「シェバン(シバン、シェバング)」といいます。「#!」に続けてどのインタープリタ(シェルなどのプログラム)で実行するかを指定するもので、cshで動作させる場合は「#!/bin/csh」などと記述します。シェバンの記述がなくても動作はしますが、意図しない動作を防ぐために原則的には記述した方がよいでしょう。
なお、シェルスクリプトのファイル名は慣習的に「.sh」という接尾辞(suffix)を付与します。ただし「.txt」などと同様にOSに対しての意味はないため、「.sh」のつかないシェルスクリプトも存在します。

●変数
シェルスクリプトでは変数を扱うことができます。
変数への値の代入と値の参照は以下のように行います。

例)変数「var」へ文字列「Essentials」を代入する
 var="Essentials"
 ※変数と"="、値の間にスペースを入れてはいけません。

例)変数「var」の値を参照する
 $var
 「echo $var」などとすると、変数varの値が標準出力へ出力されます。

●引数
シェルスクリプトでは引数を扱うこともできます。
引数の数は「$#」、引数は先頭から「$1」「$2」などと参照できます。
例)スクリプトで引数を扱う


●繰り返し(ループ)処理
シェルスクリプトでは、例えば「カレントディレクトリのにある全てのテキストファイル *.txt をすべてコピーしたい」というような場合、処理をループ(繰り返し)で行うことができます。
以下は、forを使ったループ処理の書式です。

 ※do~doneまではループ内の処理なので、通常は(読みやすさのために)スペースまたはタブで文字下げします。

「変数」には、「値のリスト」にある値が一つずつ代入され、処理を行います。
例えば、カレントディレクトリに「a.txt」「b.txt」「c.txt」が存在する場合、for文を使って以下のように処理することができます。

例)カレントディレクトリにある「.txt」で終わるファイルすべてをコピーする

変数「$text」には「a.txt」「b.txt」「c.txt」が順に代入され、do~doneの処理「cp $text $text.cp」が実行されます。したがって、本処理が実行されると「a.txt.cp」「b.txt.cp」「c.txt.cp」というファイルが作成されます。

●終了ステータス(リターンコード)
Linux(Unix)のコマンドは、コマンドの実行結果を終了ステータス(リターンコード)で返すという仕組みが組み込まれています。
例えば「ls」とコマンドを実行すると、カレントディレクトリにあるファイル一覧が表示されてコマンドが終了します。直後にechoコマンドで「$?」という変数を表示すると、終了ステータスを参照することができます。

例)終了ステータスを参照する
 $ ls
 file1.txt file2.txt
 $ echo $?
 0

変数「$?」には、直前に実行したコマンドの終了ステータスが格納されます。
終了ステータスは以下の意味を持ちます:
・コマンドが正常終了したとき ... 0
・コマンドが異常終了したとき ... 1~255

lsコマンドで存在しないファイルを指定した際はエラーになりますが、終了ステータスを参照すると以下のようになります。
例)終了ステータスを参照する(コマンドが異常終了した時)
 $ ls file.txt
 ls: cannot access file.txt: No such file or directory
 $ echo $?
 2

終了ステータスがどのような意味をもつのかは、manまたはinfoコマンドのマニュアルに書かれていることがあります。

終了ステータスを活用すると、コマンドの実行結果次第で処理を分岐させることもできます。
例えば、分野「コマンドラインの基本」で学習したメタキャラクタに以下のようなものがあります:
・コマンド1 && コマンド2 ... コマンド1が成功した場合、コマンド2を実行
・コマンド1 || コマンド2 ... コマンド1が失敗した場合、コマンド2を実行
この「&&」「||」はいずれもコマンド1の終了ステータスを判断しています。
メタキャラクタはシェルスクリプトでも利用できますので、以下のような処理を書くこともできます。

例)ディレクトリを作成し、成功した場合にファイルを移動させる
 mkdir tmp && mv *.txt tmp

例)ディレクトリを作成し、失敗した場合はエラーメッセージを表示する
 mkdir tmp || echo "mkdir error"

●実行方法
シェルスクリプトを実行するには以下の方法があります。
・実行権を付与して実行
・bashコマンド または sourceコマンドの引数に渡して実行

・実行権を付与して実行
Linux(Unix)のファイル・ディレクトリには以下の三つの権限が付与されています。
 読み取り権(r:read) ... 参照することができる
 書き込み権(w:write) ... 書き込み・更新することができる
 実行権(x:execute) ... 実行することができる
※権限(パーミッション)の詳細は、分野「ファイルのパーミッションと所有権を管理する」にて学習します。

ファイル・ディレクトリに与えられている権限は、コマンド「ls -l」で確認することができます。


実行権が付与されたファイルは、lsコマンドなどと同様にファイルをコマンドとして扱うことができるようになります。
ただし、環境変数PATHに設定されていないディレクトリのスクリプトを実行する際は、パスを指定することを忘れないでください。
例えばディレクトリ「/home/user01/bin」へ保存したスクリプト「home.sh」を実行するには以下の方法があります。

例)実行権が付与されたスクリプト「home.sh」を実行する
○絶対パスを指定して実行
 $ /home/user01/bin/home.sh
○ディレクトリを移動して相対パスで実行
 $ cd /home/user01/bin
 $ ./home.sh
○環境変数PATHに「/home/user01/bin」を追加して実行
 $ export PATH="/home/user01/bin:$PATH"
 $ home.sh
※環境変数PATHについては、分野「コマンドラインの基本」を参照してください。

なお、実行権が与えられていない場合に上記のように実行すると、エラーが出力されて実行できません。
例)実行権が与えられていないスクリプトを実行する
 $ ./script.sh
 -bash: ./script.sh: Permission denied
 → Permission denied=権限が不正 という理由のエラーになる

・bashコマンド または sourceコマンドの引数に渡して実行
コマンドbashやsourceは、引数に指定されたファイルを実行します。
例)スクリプト「home.sh」を実行する
 $ bash home.sh
 $ source home.sh

この時のスクリプトには、実行権が付与されている必要はありません。

sourceコマンドとbashコマンドには以下のような違いがあります。
・sourceコマンド ... 指定したシェルスクリプトを読み込み、現在のシェルで実行する。スクリプトで設定した変数はシェル変数として現在のシェルで参照される。また、現在のシェルに設定しているシェル変数もスクリプトで参照される
・bashコマンド ... シェルを起動してシェルスクリプトを実行する。スクリプトで設定した変数はスクリプト内(起動したシェル内)で完結し、現在のシェルに設定しているシェル変数もスクリプトへ反映されない

以下は、sourceコマンドとbashコマンドの実行例です。
例)シェル変数SAMPLEの扱い

なお、環境変数はsource、bashに関わらず参照されます。
上に戻る

解答の誤り

投稿日 2023/04/26

この問題の解答、または問題文に誤りがあります。訂正いただければ幸いです。
問題のスクリプトには、実行パーミッションが与えられていません。従って、このまま実行すると、
-bash: ./test.sh :Permission denied
というエラーが出力されるのが正解です。問題文は、
chmon +x test.sh
が書かれていません。従って、上記3行目のエラーが出されます。正解答としている、「なにも出力されない」は誤りです。

スタッフからの返信

s staff_khira0410

2023/04/27 08:16

yo1447 さん ご指摘の点を修正いたしました。 ご報告、誠にありがとうございました。

この投稿に対して返信しませんか?