変数を使用する
一般的な変数の設定と参照
変数に値を設定する
code:bash
VAR1=123456
code:bash
VAR2=hogehoge
code:bash
VAR3=" a b c d e f g "
→ 他のプログラミング言語と同様に = を使用する。
シェルスクリプトでも C言語などと同様に = を使用することで変数に値を設定することができる。ただし、C言語とは違い = の前後にスペースがあってはいけない。
また、変数名の大文字と小文字は区別されるため変数 VAR と変数 var は別物として扱われる。さらにシェル変数に「型」は存在しないので、文字列や数値を区別なく設定できる。
ポイントをまとめると以下のとおりとなる。
1. = を使う
2. 値の設定時は変数名の先頭に $ を付けない ($ は参照時のみ)
3. = の前後にスペースを入れない (前後にスペースがあるとエラー)
4. 型は存在しない (declare コマンドや typeset コマンドで似たようなことができるが推奨はしない)
5. 変数名の大文字・小文字は区別される (VAR と var は別物)
特に「2」は初心者が犯しがちなミスなので注意すること。
コマンドの実行結果を変数に設定する
標準出力のみを変数に設定する
code:bash
VAR=command
→ 画面に表示されるコマンドの実行結果 (標準出力に出力される文字列) を全て変数に設定する。
計算結果、文字列の編集結果、等、コマンドの出力を変数に設定したい場合は、「」(バッククォート) を使用する。
ただし、この方法で変数に設定されるのは標準出力に出力されたコマンドの実行結果のみで、標準エラー出力に出力されたコマンドの実行結果は変数には設定されない。
結果的に、
コマンドが正常に実行された場合は結果が変数に設定され (画面上にはなにも出力されない)
エラーが発生した場合は画面上にエラーが出力される
ことになる。
code:terminal
$ VAR=date
$ echo $VAR
2007年 5月 26日 土曜日 02:06:23 JST
$ VAR=ls hogehoge
ls: hogehoge: そのようなファイルやディレクトリはありません
標準エラー出力のみを変数に設定する
コマンドの標準エラー出力のみを変数に設定したい場合は、以下のようにする。
code:bash
VAR=command 2>&1 >/dev/null
→ コマンドのエラーメッセージのみを変数に設定する
あらかじめ >/dev/null で元の標準出力を捨てつつ、2>&1 で標準エラー出力を標準出力にリダイレクトすることで、標準エラー出力のみを変数に設定することが可能になる。
code:terminal
$ ls hoge >/dev/null
ls: hoge: そのようなファイルやディレクトリはありません
#↑ 標準エラー出力にエラーメッセージが出力されいてる $ VAR=ls hoge 2>&1 >/dev/null
$ echo $VAR
ls: hoge: そのようなファイルやディレクトリはありません
#↑ 標準エラー出力のエラーメッセージが変数に設定されている $ touch hoge
$ VAR=ls hoge 2>&1 >/dev/null
$ echo $VAR
#↑ 元の標準出力は捨てているので、エラーが発生しなかった場合は変数は空になる 標準出力・標準エラー出力の両方を変数に設定する
コマンドの実行結果を、エラーも含めて変数に設定したい場合は次のようにする。
code:bash
VAR=command 2>&1
→ 標準出力に加えて標準エラー出力に出力されるコマンドの実行結果を全て変数に設定する。
リダイレクトを指定することで、エラーが発生した場合もコマンドの実行結果を変数に取得することができるようになる。この指定方法だとコマンドの実行結果は、エラーメッセージも含めて画面上には一切出力されないことになる。
code:terminal
$ VAR=ls hogehoge
ls: hogehoge: そのようなファイルやディレクトリはありません
$ echo $VAR
$ VAR=ls hogehoge 2>&1
$ echo $VAR
ls: hogehoge: そのようなファイルやディレクトリはありません
バッククォートの代替機能
バッククォートと同様の機能は $(command) でも実現可能。
code:bash
VAR=$(command)
→ 実行結果はバッククォートを使用した場合と同じになるが、より高機能。
code:terminal
$ echo $VAR
2007年 5月 26日 土曜日 03:01:30 JST
$ VAR2=$(ls hogehoge)
ls: hogehoge: そのようなファイルやディレクトリはありません
$ echo $VAR2
$ VAR2=$(ls hogehoge 2>&1)
$ echo $VAR2
ls: hogehoge: そのようなファイルやディレクトリはありません
このようにコマンドの実行結果、つまりコマンドが標準出力に出力する文字列を変数に格納したい場合は、<code></code> (バッククォート)もしくは $() を使用する。
また、$() はより高機能なので、以下のようにネストも可能である。
code:terminal
$ var=$(expr $(expr $(date '+%Y') + $(date '+%m')) + $(date '+%d'))
$ echo $var
2041
(この計算に特に深い意味はない。ただのネストの使用例である。)
補足 - バッククォートに関して
UNIX 環境での Bシェルとの互換性を考慮してバッククォートを推奨していたが、最近では Bシェルを使う機会もほぼないと思うので、バッククォートではなく $() を推奨する。当サイト内の <code></code> は適宜 $() に読み替えてほしい。
ちなみに筆者はタイプするのが面倒なので、普段はバッククォートを使用している。
変数の値を参照する
変数 VAR1 の値を表示する
code:bash
echo $VAR1
変数 VAR の値と「1」を表示
code:bash
echo ${VAR}1
変数 VAR2 の値と変数 VAR3 の値を表示
code:bash
echo ${VAR2}${VAR3}
変数の値を他の変数へ設定する
code:bash
VAR="$VAR1"
変数 VAR に変数 VAR1 の値を設定する。
変数 VAR に変数 VAR の値と「1」を設定
code:bash
VAR="${VAR}1"
変数 VAR の値の最後に「1」を付加する。
変数 VAR に変数 VAR2 と変数 VAR3 の値を結合した値を設定
code:bash
VAR="${VAR2}${VAR3}"
→ 変数の値を参照するには変数名の先頭に $ を付ける。
変数の値を参照する場合は変数名の頭に $ を付ける。参照する変数を明確にする場合は {} (中括弧) で変数名を囲む。
例えば上記の「$VAR1 」と「${VAR}1」は違う変数を参照する。前者は変数 VAR1、後者は変数 VAR を参照となる (変数 VAR と変数 VAR1 の両方が定義されている場合)。
code:terminal
$ VAR=hoge
$ VAR1=fuga
$ echo $VAR1
fuga
$ echo ${VAR}1
hoge1
また、変数を {} で囲むことはシェルスクリプトの可読性を高めることにも有効である。「${foo}${bar}」のように複数の変数を同時に参照する場合などは、{} を使用した方が個々の変数を区別しやすくなる。
code:terminal
$ VAR1=123456
$ VAR2=abcdefg
$ VAR3=" a b c d e f g "
$
$ echo $VAR1
123456
$ echo ${VAR}1
1
$ echo ${VAR2}${VAR3}
abcdefg a b c d e f g
変数の特殊な参照方法
→ 変数の状態に応じて振る舞いを変える特殊な参照方法。
変数に値が設定されていない場合に一時的に値を与えて参照する、などの特殊な参照が可能である。だが、これらをむやみに使用するとシェルスクリプトの可読性が低下し、思わぬバグを生む可能性があるので、あまり多用はしないほうがよいだろう。
特殊な参照方法一覧表
table:_
参照方法 参照結果
${VAR=aaa} 変数 VAR が未使用の場合に限り、変数VARへ文字列「aaa」を代入し文字列「aaa」を返す。変数VARがNULL値を含み既に使用されている場合は、変数 VAR への代入を行わず、変数 VAR の値を返す。
${VAR:=aaa} 変数 VAR が未使用もしくは NULL の場合に限り、変数 VAR へ文字列「aaa」を代入し文字列「aaa」を返す。変数 VAR が NULL 値の場合を除き、既に使用されている場合は変数 VAR への代入を行わず、変数 VAR の値を返す。
${VAR-aaa} 変数 VAR が未使用の場合に限り、文字列「aaa」を返す。変数 VAR が NULL 値を含み既に使用されている場合は、変数 VAR の値を返す。また、変数 VAR が使用済み・未使用に関わらず、変数 VAR への代入は行われない。
${VAR:-aaa} 変数 VAR が未使用もしくは NULL 値の場合に限り、文字列「aaa」を返す。変数 VAR が NULL 値以外の値で既に使用されている場合は、変数 VAR の値を返す。また、変数 VAR が使用済み・未使用に関わらず、変数 VAR への代入は行われない。
${VAR+aaa} 変数 VAR が NULL 値も含み既に使用されている場合に限り、文字列「aaa」を返す。変数 VAR が未使用の場合は、NULL 値を返す。また、変数 VAR が使用済み・未使用に関わらず、変数 VAR への代入は行われない。
${VAR:+aaa} 変数 VAR が NULL 値以外で既に使用されている場合に限り、文字列「aaa」を返す。変数 VAR が NULL 値もしくは未使用の場合は、NULL 値を返す。また、変数 VAR が使用済み・未使用に関わらず、変数 VAR への代入は行われない。
NULL 値に関して
ここでの NULL 値とは、VAR="" や VAR= のように値が空 (空文字) の状態を意味することとする。
特殊な参照方法の実行結果まとめ
https://gyazo.com/ed5825182ff2e10674f8960f2921de50
値の設定・・・変数 VAR に文字列 "aaa" が設定されるかされないか。
返す値・・・変数 VAR を表にある形式で参照した時の値 (echo xxx などと実行したときに出力される値)。
変数の値を変数名として値を参照する
code:bash
eval echo '$'$VAR
→ eval コマンドを使用して変数を二重に展開する。
eval コマンドで 変数 VAR を展開してから、さらにクォートしておいた $ を利用してシェルが変数を再展開する。
これによって変数 VAR に設定されていた値を変数として参照することが可能になる。そのために一つ目の $ は、1回目の変数展開時にシェルに解釈されないようクォートする必要がある。
code:terminal
$ FOO="BAR"
$ BAR="SUCCESS"
$ eval echo '$'$FOO
SUCCESS
#↑変数 FOO に設定されている値を変数名として参照している。 eval コマンドにより、最初に変数 FOO が展開され、コマンドラインは echo $BAR となる。さらにその後、echo コマンドにより変数 BAR が展開される。そのため結果的に、変数 FOO に設定されていた変数名の変数を参照することになる。例えば変数 FOO に "foo" が設定されていた場合は、変数 foo の値を参照することになる。
変数を削除する
code:bash
unset VAR
→ unset コマンドで変数を削除する。
変数を削除するには unset コマンドに削除したい変数名を指定して実行する。変数名を指定する際には $ は付けずに変数名のみを指定する。
unset コマンドが実行されると、対象となった変数は値が削除されるだけではなく、未使用の状態に戻る。
code:terminal
$ echo ${VAR-"変数 VAR は未使用です。"}
変数 VAR は未使用です。
$ VAR="hogehoge"
$ echo ${VAR-"変数 VAR は未使用です。"}
hogehoge
$ VAR=
$ echo ${VAR-"変数 VAR は未使用です。"}
#↑NULL 値でも変数は使用済みと判断されるので、NULL が出力される。 $ unset VAR
$ echo ${VAR-"変数 VAR は未使用です。"}
変数 VAR は未使用です。
#↑unset コマンドを実行すると未使用状態になる。つまり単純に値が NULL にされるわけではなく、変数そのものが削除されていることになる。 変数を読み取り専用に設定する
code:bash
readonly VAR="hogehoge"
→ 変数設定時に readonly を指定して読み取り専用にする。
変数設定時に readonly を指定することで、その変数は以後読み取り専用となり、値を変更しようとするとエラーになる。つまり readonly にすることで、変数を定数化することが可能になる。
code:terminal
$ readonly VAR="hogehoge"
$ echo $VAR
hogehoge
$ VAR="fugafuga"
bash: VAR: readonly variable
$ echo $VAR
hogehoge
処理の途中で変えられたくない値は readonly を指定しておくことで、値が変更されることによるバグを抑止することができる。
特殊な変数とその参照
特殊変数とは
シェルによって自動的に値が設定される特殊な変数がいくつかあり、それら特殊な変数を参照することにより、様々な情報を取得することができる。
特殊変数一覧表
table:_
変数名 自動的に設定される値
$? 直前に実行されたコマンドの終了ステータスが設定される変数
$! バックグラウンドで実行されたコマンドのプロセスID が設定される変数
$- set コマンドで設定されたフラグ、もしくはシェルの起動時に指定されたフラグの一覧が設定される変数
$$ コマンド自身の PID (プロセスID)が設定される変数
$# 実行時に指定された引数の数が設定される変数
$@ $* シェルスクリプト実行時、もしくは set コマンド実行時に指定された全パラメータが設定される変数
$LINENO この変数を使用している行の行番号が設定される変数
${PIPESTATUS[@]} パイプで連結した各コマンドの終了ステータスが設定される変数(配列)
$1, $2, ..., ${10}, ... set コマンドもしくはシェルスクリプトの N個目の引数が設定される変数 (位置パラメータと呼ばれる)
各特殊変数の詳細
直前に実行されたコマンドの終了ステータスが設定される変数
code:bash
$?
コマンド正常終了の場合は「0」、異常終了の場合は「0 以外」がセットされる。
シェルスクリプトでは exit コマンドに与えた引数がそのシェルスクリプトの終了ステータスとなる。例えば exit 2 と書いたならば、そのシェルスクリプトの終了ステータスは「2」。
関数の return の場合も同様に、指定した引数がその関数の終了ステータスとなる。
バックグラウンドで実行されたコマンドのプロセスID が設定される変数
code:bash
$!
sleep 100 & のように & を付けて実行すると、そのコマンドはバックグラウンドで実行される。この場合、変数 $! には sleep コマンドの PID (プロセスID) がセットされている。
set コマンドで設定されたフラグ、もしくはシェル起動時に指定されたフラグの一覧が設定される変数
code:bash
$-
変数 $- の値が「abc」ならばフラグは「-abc」ということになる。
コマンド自身の PID (プロセスID) が設定される変数
code:bash
$$
シェルスクリプト内で echo $$ のように記述すると、そのシェルスクリプトが実行されたときの PID 取得できる (PID は OS 上で一意になるよう割り当てられる)。
この変数を使用したテクニックで、シェルスクリプト内で作成するファイル名の拡張子に変数 $$ を指定するというものがある (e.g. tempfile.$$ )。変数 $$ を拡張子に指定することで、シェルスクリプト実行毎に作成するファイル名を変えることができるので、同一シェルスクリプトを同時実行した場合に、同時実行された各スクリプトが同時に同一ファイルに出力してしまうことを防止できる。
実行時に指定された引数の数が設定される変数
code:bash
$#
→ シェルスクリプト実行時、もしくは set コマンド実行時のパラメータ数が設定される変数。
シェルスクリプト実行時、もしくは set コマンド実行時に指定されたパラメータ数は変数 $# に自動で設定される。 指定された引数の数をチェックしたい場合にはこの変数を使用する。
たとえば $ ./command.sh AAA BBB CCC のように実行された場合、シェルスクリプト command.sh 内で変数 $# を参照するとその値は「3」となる。
以下は変数 $# を使用したパラメータチェックを行うシェルスクリプト (pram_check.sh) の例。
code:bash
echo "引数が指定されていません!!!" 1>&2
exit 1
else
echo "指定された引数は$#個です。"
fi
exit 0
これを引数なしと、引数ありで実行してみる。
code:terminal
$ ./param_check.sh
引数が指定されていません!!!
$ ./param_check.sh 1
指定された引数は1個です。
$ ./param_check.sh 1 2
指定された引数は2個です。
$ ./param_check.sh 1 2 3
指定された引数は3個です。
引数の数により上記シェルスクリプト内 6行目のメッセージに使用されている変数 $# の値が変化しているのが分かる。このように変数 $# の値を参照することで、シェルスクリプト実行時のパラメータ数を確認することが可能である。
シェルスクリプト実行時、もしくは set コマンド実行時に指定された全パラメータが設定される変数
code:bash
$@
code:bash
$*
→ シェルスクリプトもしくは set コマンドの全引数が設定される変数。
シェルスクリプト実行時、もしくは set コマンド実行時に指定された全パラメータは変数 $@ と変数 $* に自動で設定される。
全パラメータのリストを取得する場合、どちらの変数を参照しても結果は同じであるが、ダブルクォート ("") で囲んだ場合の動作が異なる。
詳細は以下のとおりである。
変数 $@ を「""」で囲んだときは、格納されている個々の値をそれぞれ「""」で囲んだ状態で展開される。
例えば、格納されている値が、
「aaa」「bbb」「ccc」 (※ set "aaa" "bbb" "ccc")
ならば、「"$@"」は、
"aaa" "bbb" "ccc"
のように展開される。
変数 $* は $@ とは異なり、「""」で囲んだときは、格納されている全ての値を一つの「""」で囲んだ状態で展開される。
例えば、格納されている値が、
「aaa」「bbb」「ccc」 (※ set "aaa" "bbb" "ccc")
ならば、「"$*"」は、
"aaa bbb ccc"
のように展開される。
例えば、以下のようなシェルスクリプト (all_parameters.sh) を実行する。
code:bash
echo '1."$@"の動作---------------------------------------'
for i in "$@"
do
echo $i
done
echo ""
echo '2."$*"の動作---------------------------------------'
for i in "$*"
do
echo $i
done
このシェルスクリプト all_parameters.sh の実行結果は、以下のとおりとなる。
code:terminal
$ ./all_parameters.sh aaa bbb ccc ddd eee fff ggg
1."$@"の動作---------------------------------------
aaa
bbb
ccc
ddd
eee
fff
ggg
2."$*"の動作---------------------------------------
aaa bbb ccc ddd eee fff ggg
$
上記の実行結果のとおり、格納されている値は同じでも動作がまったく異なっているのが分かる。
「"$@"」で展開した値は、各値が個別に変数 i に格納されるため、それぞれ1行ずつ計7行出力される。それとは異なり「"$*"」で展開された値だと、全ての値が一度に変数iに格納されるため、1行で全ての値が出力される。
つまり、変数展開時に for 文は以下のような状態にある。
code:bash
# "$@"
for i in "aaa" "bbb" "ccc" "ddd" "eee" "fff" "ggg"
code:bash
# "$*"
for i in "aaa bbb ccc ddd eee fff ggg"
このように、シェルスクリプトで for 文を使用し、各パラメータに対して個別の処理を行いたい場合は、「"$*"」ではなく、「"$@"」を使用しなければならない。
変数を使用している行の行番号が設定される変数
code:bash
$LINENO
デバッグに便利な行番号が設定されている変数。例えば、シェルスクリプト内の 5行目でこの変数を使用したとすると、そこでの変数 LINENO の値は「5」となる。
パイプで連結した各コマンドの終了ステータスが設定される変数(配列)
code:bash
パイプ (|) により連結された各コマンドの終了ステータスが設定設定されている変数(配列)。
変数 $? ではパイプの一番最後にあるコマンドの終了ステータスしか参照することができないが、この変数を使用することで、パイプの先頭や途中にあるコマンドの終了ステータスを参照することができる (残念ながら bash のみで ksh では使用できない)。
位置パラメータ
code:bash
$0
$1
$2
$3
・・・
→シェルスクリプトもしくは set コマンドの各引数が個別に設定される変数。
$0、$1、$n は、位置パラメータと呼ばれる特殊変数である。
シェルスクリプト実行時、もしくは set コマンド実行時にパラメータに指定された値は、位置パラメータと呼ばれる特殊な変数に自動で設定される。
これら位置パラメータに「$1="1234"」のように、自分で任意の値を設定することはできない。自分で任意の値を設定するには set コマンドを使用する必要がる。
位置パラメータの例 1
code:terminal
$ /usr/local/bin/command.sh -a aaa -b bbb -c ccc
上記のように実行した場合、シェルスクリプト command.sh 内では変数 $1 を参照することにより、一番先頭に指定されたパラメータ "-a" を得ることができる。
table:_
col 1 col 2 col 3 col 4 col 5 col 6 col 7
$ /usr/local/bin/command.sh -a aaa -b bbb -c ccc
↑ ↑ ↑ ↑ ↑ ↑ ↑
$0 $1 $2 $3 $4 $5 $6
位置パラメータの例 2
10番目以降の位置パラメータは、参照時に「${10}」のように番号を「{}」で囲む必要がある。そうしないとシェルは先に $1 を解釈するため、展開される値は10番目のパラメータではなく1番目のパラメータとなる。
code:terminal
$ set a b c d e f g h i j
#↑ set コマンドにて位置パラメータに a ~ j の10個の値を設定する。 $ echo $*
a b c d e f g h i j
$ echo $10
a0
#↑ $1 が先に解釈されるため、出力される値は $1 の「a」と、10の「0」で結果的に『a0』となる。 $ echo ${10}
j
位置パラメータのまとめ
table:_
変数名 自動的に設定される値
$0 実行したシェルスクリプト名が設定される。<br>$ ./test.sh と実行した場合、$0 は「./test.sh」となる。<br>$ /usr/local/bin/test.sh のようにフルパス指定で実行された場合は、「/usr/local/bin/test.sh」のようにフルパスで設定される。
$1 1番目の引数が設定される。
$2 2番目の引数が設定される。
$3 3番目の引数が設定される。
$4 ~ $9 4~9番目の引数が設定される。
${10} **10番目の引数が設定される。**参照するには「$10」ではなく「${10}」のように「{}」で囲む必要がある。前者の場合は先に「$1」が解釈されるため、目的どおりの動作にならない。
${11} ~ ${100} 11番目~100番目の引数が設定される。
環境変数
環境変数は、システム全体の動作に関連する値が設定されている (もしくはユーザが値を設定する) 変数。環境変数として設定されている変数名とその値は env コマンドで確認できる。
一般的な環境変数まとめ
table:_
変数名 設定される値
$PS1 **プロンプトに使用される文字列が設定されている環境変数。**この変数の値を変更することで、プロンプトの表示形式を変更することができる。
$PS2 **コマンドが複数行にわたった場合のプロンプトに使用される文字列が設定されている環境変数。**環境変数 PS1 と同様に値を変更することにより、プロンプトの表示形式を変更することができる。
$PATH **コマンドが格納されているディレクトリのパスが設定されている環境変数。**パスは「:」(コロン)区切りで複数設定可能。コマンド実行時には、この環境変数 PATH に設定されているディレクトリでコマンドの本体が自動的に検索される。つまり、環境変数 PATH に「/bin」を設定することにより、コマンドを「/bin/ls」のようにフルパスで指定しなくとも、「ls」のようにコマンド名のみ指定での実行が可能になる。
$TZ **タイムゾーンが設定されている環境変数。**特に変更するようなことは無いであろうが、古い UNIX 環境で昨日の日付を取得したい場合などに、一時的に変更する場合がある。
$PWD カレントディレクトリのパスが設定されている環境変数。「PS1='[${PWD}]$ '」のように環境変数PS1に設定すると、プロンプトにカレントディレクトリが表示されるようになる。
$IFS **デリミタ(区切り文字)として使用される値が設定されている環境変数。**IFS は "Internal Field Separator" の略。デフォルトではタブ、スペース、改行が設定されている。for 文の値リストの区切りや、read コマンドで読み込む値の区切りなどに使用される。
配列を使用する