12.1 シェル変数と環境変数
Linux Essentials Online Text | 2021/07/29

プログラミングをする上で非常に重要な考え方が必要なのが「変数」です。変数は、簡単に言うと「入れ物」で、中に数値や文字列が入ります。中学生の数学のときに習ったxやyがそれにあたります。シェルスクリプトプログラミングでは、変数に数値や文字列を代入し、それを利用することができます。変数の代入は、=を使って行うことができます。

シェルスクリプトプログラミングには、「シェル変数」と「環境変数」という2種類の変数があります。「シェル変数」は、現在実行しているシェル上でのみ有効です。逆に「環境変数」は、その設定が削除されるまで別のシェル、及びシェルで実行されるプログラムで有効になります。

echoコマンド

echoコマンドは標準出力に出力するためのコマンドです。変数は「$」をつけて出力することができます。

書式:

echo [オプション] 文字列

主なオプション:

-n改行を抑制します。(通常の出力は改行されますが、このオプションがあると改行されません。)

<実習: シェル変数の表示>

シェル変数を作成し、設定した変数を引き出してみます。

$ abc=123
$ echo $abc
123

1行目で変数abcを作成し、中に123 格納しています。言い換えると「abc」という箱の中に「123」を入れたということです。
変数は「$(ダラー)」を使って表現します。これにより、変数abcは「$abc」と表現されます。
つまり、2行目は「変数abcをecho(標準出力)する」という意味になります。

export コマンド

環境変数の設定には、exportというコマンドを使用します。

書式:

export [シェル変数]
export [変数=値]

exportコマンドは予め設定されたシェル変数を指定するか、exportコマンド上で定義することで、環境変数を作成することができます。既存の環境変数の値を変更することもできます。
exportコマンドのみで実行した場合は、現在設定されている環境変数の一覧が表示されます。

<実習: 環境変数を設定する

$ export abc
$ export xyz=234
$ export | tail -2
declare -x abc="123"
declare -x xyz="234"

1行目:既に設定しているシェル変数abcを環境変数に変換しています。
2行目:環境変数xyzを作成しています。
3行目:環境変数一覧の末尾2行を表示します。

シェル変数と環境変数の違い

「シェル変数」と「環境変数」の違いはちょっとわかりにくいかも知れませんので、もう一度説明します。

「シェル変数」は現在実行しているシェル上でのみ有効です。例えば新しいbashを更に起動しても、その変数は受け継がれないため、設定を入力したシェルでしか使用することができない変数です。

「環境変数」は現在実行しているシェル上だけでなく、そのシェルから他のシェルに移動したり、シェルスクリプトを使っても利用することができる変数です。例えばbashを更に起動したり、シェルスクリプトを起動したりしても、その変数を利用することができます。ただし、どちらの変数もログアウトすると削除されます。変数を維持するには別の設定が必要です。

<実習:シェル変数と環境変数の違いを確認する>

まずはシェル変数を作成します。

$ LPI=”Linux Professional Institute”
$ echo $LPI
Linux Professional Institute

シェル変数が作成されたことを確認したら新しいbashを起動して、新しいbash上でシェル変数を確認してみましょう。新しいbashを起動するにはbashコマンドを実行します。

$ ps
  PID TTY          TIME CMD
 1671 pts/0    00:00:00 bash
 1716 pts/0    00:00:00 ps
$ bash
$ ps
  PID TTY          TIME CMD
 1671 pts/0    00:00:00 bash
 1733 pts/0    00:00:00 bash
 1772 pts/0    00:00:00 ps
$ echo $LPI

$ exit
$ echo $LPI
Linux Professional Institute
$ ps
  PID TTY          TIME CMD
 1671 pts/0    00:00:00 bash
 1716 pts/0    00:00:00 ps

上記の内容を細かく解説しましょう。

1行目:psコマンドでプロセスIDを確認します。
上記の例では、現在のbash(シェル)のプロセスが「1671」であることがわかります。プロセスIDは環境によって割りあてられる数値ですので、環境によって数値が異なります。

5行目: bashコマンドを実行します。これは bash(シェル)を起動するコマンドです。

6行目:psコマンドを実行します。
プロセスID「1733」のbashというプロセスが増えていることがわかります。つまり、これはbashコマンドによって新たなシェルが起動されており、見た目にはわかりませんが“プロセスID「1733」のシェル”にいる状態である、ということです。

11行目:echoコマンドを実行します。
12行目の通り、何も表示されないことを確認しましょう。上記で説明したとおりシェル変数は作成したシェル上でしか有効になりません。つまり、プロセスID「1671」のシェルで作成したシェル変数はプロセスID「1671」のシェルでのみ有効であり、プロセスID「1733」のシェル上では有効ではない、ということです。

13行目:exitコマンドを実行します。
これは現在のシェルから抜けるためのコマンドで、プロセスID「1733」のシェルを停止することを意味します。つまり、元いたプロセスID「1671」のシェルに戻ってくるということです。

14行目:シェル変数LPIをechoします。
元いたプロセスID「1671」のシェルに戻ってますので、最初に登録していたシェル変数「LPI」が表示されます。

16行目:プロセスIDを確認します。
プロセスID「1733」のシェルが消えています。つまり、“新しいシェル”が停止し、元いたシェルに戻ってきた、ということです。

図解してみると、以下のようになります。

では次に、exportコマンドを使ってシェル変数「LPI」を環境変数にして確認してみます。

$ export LPI				# LPIを環境変数に設定
$ echo $LPI				# LPIが表示されることを確認
Linux Professional Institute
$ bash					# 新しいbashを起動
$ echo $LPI				# LPIが表示されることを確認
Linux Professional Institute
$ exit

1行目のように、シェル変数LPIを環境変数に変更し、先ほどと同じ作業をしてみます。今度はbash起動後でも$LPIをechoしても、変数が返ってくることに注目してください。
これにより、環境変数は別のシェルでもその値が引き継がれていることがわかります。

こちらも、bashコマンドを実行する前後でpsコマンドを使ってプロセスIDを確認してみてください。新しいプロセスIDのbash上でも変数LPIの値が出力されることがわかります。

変数の削除(set,unset)

設定された変数(シェル変数、環境変数)はsetコマンドを用いることで一覧を確認することができます。
また、unsetコマンドを使用することで、設定されている変数を削除することができます。

set
unset 変数($無し)

また、設定された環境変数を削除する場合は、unsetを利用します。exportコマンドで値を設定せずに入力することで削除することも可能です。

<実習: unsetを用いた変数の削除>

今までに設定した変数を削除してみましょう。ログアウトなどをして消えてしまっている場合は、いずれか一つで構いませんので、シェル変数か環境変数を設定してから実施してみましょう。

$ set | grep -e "abc\|xyz\|LPI"
LPI='Linux Professional Institute'
abc=123
xyz=234
$ unset abc
$ unset xyz
$ unset LPI
$ set | grep -e "abc\|xyz\|LPI"
$

なお、数値を空欄にして設定する、という方法でも値を削除することができます。

$ acb=
$ xyz=
$ LPI=

システム変数と環境変数PATH

シェル変数や環境変数はユーザが自由に定義することができます。ユーザが定義したシェル変数や環境変数をユーザ変数と呼びます。一方で、システムで管理される変数もあります。これをシステム変数と呼びます。

主に言語環境やパス、シェル等、システムを利用するにあたり、ユーザが作業しやすいように環境をカスタマイズするために予め設定されている変数です。ここではシステムに設定されている環境変数を紹介します。

例えば、lsコマンドは、以下のように実行します。

$ ls

「ls」はコマンドとして扱っていますが、実際には「指定したディレクトリ内のファイルやディレクトリを表示する」という動作を行う「プログラムファイル」です。

Windowsでプログラムを起動する際、デスクトップ上のアイコンやメニューバーから起動したいアイコンを選んで実行しますが、これはプログラムファイル本体ではありません。ですから、これらのアイコンを削除してもプログラムはアンインストールされることはありません。プログラムファイル本体は「Program Files」と呼ばれる別の場所に格納されているからです。

デスクトップやメニューバーにあるアイコンは、プログラムファイル本体が格納されている場所を記したリンクファイルになっており、このリンクファイルを実行するとはリンク先のプログラムファイル本体を呼び出します。つまり、リンクファイルの実行=プロラムファイル本体の実行ということになるため、プログラムが起動するのです。

どのOSでも、プログラムを実行するときはプログラムファイルそのものにアクセスしなければ実行することはできません。つまり、「ls」だけを入力しようとしてプログラムを実行するなら、その場に「ls」という名前のファイルが存在していなければならないのです。

しかし、「ls」コマンドは「指定したディレクトリ内のファイルやディレクトリを表示する」プログラムですが、表示された中には「ls」というファイル名は見当たりません。でも実際に「ls」と入力して実行できているのですから、何処かにあるはずのlsというファイルを実行している、ということになるのです。

では、これは何処から呼び出されたのでしょうか?

実は、「ls」というプログラムファイルは /usr/bin/の配下に置いてあります。
試しに、/usr/bin/lsを実行してみます。lsコマンドと同じ結果が表示されることがわかると思います。

$ /usr/bin/ls

強いて言えば、色がついていない事が違うくらいでしょうか。
これは、CentOSでは、lsコマンドに「–color=auto」がaliasとして設定されているからです。

$ type -a ls
ls は `ls --color=auto' のエイリアスです
ls は /usr/bin/ls です
$ /usr/bin/ls --color=auto

lsをはじめとする各種コマンドは、/usr/binや/usr/sbinディレクトリにプログラムとして格納されていますが、Linuxのコマンドは、用途に応じて格納する場所が複数あります。また、上記以外の場所にもプログラムが格納される可能性があります。例えば、自ら作成したプログラム等は、ホームディレクトリと呼ばれる自分のディレクトリにしか置けません。

このように、プログラムがいろいろな場所に散見されるようになると、コマンドやプログラムを実行する度にいちいちプログラムの場所を探し出さなければならず、非常に面倒です。

そこで、Linuxシステムでは「環境変数PATH」というものを設定しました。「環境変数」とはシステム変数の一つで、OSの利用を快適にするための設定値です。「環境変数PATH」は環境変数の一つで、コマンドプログラムの場所を登録するためのシステム共通の変数です。

環境変数はexportコマンドで確認することができ、以下が環境変数PATHです。

$ export | grep PATH
declare -x PATH="/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/lpic-user/.local/bin:/home/lpic-user/bin"

“PATH=”の後に「:(コロン)」で区切られて、パスが羅列されています。ここに書かれているパスは、ユーザがコマンド(つまりはプログラム)を実行した時に、ファイルを検索する場所を示しています。

上記の場合、プログラムを実行しようとすると「/usr/local/bin」「/usr/bin」「/usr/local/sbin」「/usr/sbin」「/home/lpic-user/.local/bin」「/home/lpic-user/bin」の6つのディレクトリを検索し、実行しようとしたプログラムと同じ文字列のプログラムがあればそれを実行することができます。

この「環境変数PATH」が設定されていることで、プログラムの実行の度にプログラムファイル本体の場所を気にすること無く実行することが可能になります。

この「どのディレクトリからでもプログラムが実行できる」状態を「パスが通っている」状態と言います。具体的に言うと「PATHを通す」とは、「PATH環境変数に検索させたいディレクトリを登録すること」となのです。

つまり、自作プログラムも、環境変数PATHに記載されたディレクトリに格納すれば、パスを指定すること無くプログラム名(ファイル名)のみでコマンドライクに実行することができます。また、プログラムを作成したディレクトリを「環境変数PATH」に追加する、ということも可能です。

<実習: ホームディレクトリにパスを通す。>

試しに、ホームディレクトリにパスを通してみましょう。

$ export PATH=/home/lpic-user:$PATH
または
$ export PATH=$PATH:/home/lpic-user

PATH=の後に通したいパスを羅列していきます。パスが複数ある場合は「:(コロン)」で区切ります。最後に「$PATH」を入力したのは、既存で設定されたPATHを残すためです。このコマンドを実行すると、現在の設定に上書きするので、必ず「$PATH」は入力して下さい。先に入力しても構いません。

ちなみに、exportコマンドで設定した変数は永久的に保存されません。そのため、誤った設定を行った場合は、ログインし直せば直ります。

パスが通ると、ホームディレクトリにあるシェルスクリプトはシステムからコマンドとして認識されるようになります。

様々な環境変数

環境変数には、「PATH環境変数」だけでなく、色々な種類があります。代表的なものは覚えておきましょう。

HISTSIZE現在のシェルでのコマンド履歴保存数
HISTFILEコマンド履歴を格納するファイルパス
HISTFILESIZE$ HISTFILEに格納するコマンド履歴保存数
HOSTNAMEホスト名
HOMEホームディレクトリパス
LANGロケール(言語)
PATHコマンドやプログラムを検索するディレクトリ
PWDカレントディレクトリパス
USERログインユーザ名
LD_LIBRARY_PATH共有ライブラリを格納するファイルパス

<実習:環境変数の値を確認>

どのような値が設定されているか、echoコマンドで確認しましょう。

$ echo $HISTSIZE
1000
$ echo $HISTFILE
/home/lpic-user/.bash_history
$ echo $HISTFILESIZE
1000
$ echo $HOME
/home/lpic-user
$ echo $LANG
ja_JP.UTF-8

引用符

コマンドの中には、その実行に引用符を用いる場合があります。「'(シングルクオート)」、「”(ダブルクオート)」、「`(バッククオート)」がそれに当たります。いずれも変数を指定した時の挙動が異なります。

シングルクオートは括られた内容を全て文字列として認識します。正規表現などの特殊記号や、環境変数の「$」なども文字列として扱われます。一方でダブルクオートは括られた変数の中身を文字列として扱います。バッククオートは括られた変数の中身をコマンドとして処理し、その結果を出力します。

<実習: シングルクオートの例>

$ DATE=date
$ echo '$DATE'
$DATE

2行目のechoコマンドにはシェル変数「$DATE」が含まれているため、通常であれば「$DATE」は「date」に変換されるはずですが、今回の場合は「$」がシングルクオートで括られたために文字列として認識しており「$DATE」は変数として認識されません。結果として、括った文字列がそのまま出力されます。

<実習: ダブルクオートの例>

$ DATE=date
$ echo "$DATE"
date

上記「'(シングルクオート)」の例では括られた文字全て文字列として認識されたため「$DATE」が変換されませんでしたが、「”(ダブルクオート)」では「$DATE」を変数として認識するため「date」に変換されます。ただし、「date」はコマンドではなく文字列として認識します。

<実習: バッククオートの例>

$ DATE=date
$ echo `$DATE`
2021年 7月 28日 水曜日 13:20:02 JST

「`(バッククオート)」は、括られた変数をコマンドとして認識します。上の例ではシェル変数「$DATE」が「date」に変更されますが、「`(バッククオート)」で括られているため「date」をコマンドとして認識します。結果、ldateコマンドの実行結果が出力されます。なお、以下の方法でも変数をコマンドとして認識させることができます。

$ DATE=date
$ echo $DATE
date
$ DATE=$(date)
$ echo $DATE
2021年 7月 28日 水曜日 13:21:41 JST

おまけ:suコマンドにおける「-(ハイフン)」の有無

suコマンドは、主にroot権限を取得するときに使用します。
コマンドの実行方法は、以下の2通りです。

$ su
$ su -

rootユーザに移行するためにsuコマンドを使用しますが、「su」でも、「su -」でもrootユーザに移行することができます。結論から言うと、rootユーザに移行する場合は、「su -」を実行することをお勧めします。

-(ハイフン)の有無は、環境変数を引き継ぐかどうかに影響します。付けなければ継承、付ければ継承されません。つまり、suのみでもrootユーザになれますが、ユーザの環境設定が継承されてしまいます。

これの何がダメなのかについて解説します。下記、コマンドの実行結果を見てください。

# export | grep PATH
declare -x PATH="/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin"

# export | grep PATH
declare -x PATH="/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/lpic-user/.local/bin:/home/lpic-user/bin"

前者は「su -」でrootユーザに移行してから実行した結果です。つまり「root」の環境変数PATHです。後者が「su」でrootユーザに移行してから実行した結果です。ハイフンを付けていないため、移行前のユーザ「lpic-user」の環境変数PATHが継承されています。

両者の大きな違いは、パスの中に「/sbin」「/bin」があるかどうかです。このディレクトリには、rootユーザが使用するコマンドが格納されています。ハイフンなしでrootに移行した場合は、このディレクトリにパスが通っていませんからコマンドが実行できなくなります。

他にも、環境変数USERもハイフンなしでは移行前の「lpic-user」のままですので、これをチェックするようなプログラムは動かない、ということになります。

rootだけでなく、他のユーザに切り替わる場合も同様です。多くの場合、ユーザを切り替える理由は、「そのユーザで作業したいから」であることが大半だと思いますので、環境変数もちゃんとそのユーザのものに切り替わるように、ハイフンを付けて実行することをお勧めいたします。

PAGE TOP