このページの本文へ

Windows Info 第115回

RS4のWindows Subsystem for Linuxでは環境変数の共有が可能に

2018年02月04日 10時00分更新

文● 塩田紳二 編集● ASCII編集部

  • この記事をはてなブックマークに追加
  • 本文印刷

 Windows 10の次期アップデートであるRS4で予定されているWindows Subsystem for Linux(以下、WSL)の機能拡張には、Win32環境とWSL環境での環境変数の共有がある。

 RS2で実装されたWin32相互運用性で、WSL内でWin32デスクトップアプリケーションの実行が可能になったとき、すでにPath環境変数は、WSLとWin32で共有されていた。しかし、起動されるWSLやWin32の環境変数を指定する方法がなかった。RS4ではWSLとWin32でユーザーの指定する任意の環境変数を共有でき、このとき、環境変数が保持しているdrvfs側のファイルパスを自動変換するという機能が追加された。

WindowsとLinuxの環境変数

 共有設定を解説する前に、確認の意味を含めて、WindowsとLinuxの環境変数について解説しておく。

 環境変数とは、プログラムから読み出しが可能な環境情報で、名前が付けられていること、設定を変数の設定のように代入文の形式で行なうためにこの名がある。たとえば、コマンドラインの起動オプションのデフォルト値やプログラムの動作を変更するような場合に使われることが多い。また、前述のように起動されるプログラムやスクリプトに対するものであり、メモリ上のプロセス情報の一部として親プロセスから子プロセスに継承される。

 環境変数の特性上、起動する側で設定した環境変数は起動される側でも参照可能だが、起動された側で環境変数を使って、起動した側に情報を戻すことはできない。そもそも環境変数はプロセスに付随して作られるものであり、親プロセスから子プロセスへ環境変数が引き継がれるものの、子プロセスの環境変数はプロセスの終了時に破棄されてしまうからである。

 Win32の場合、環境変数はAPIから設定することもできるが、コマンドラインからは、

set 環境変数名=値 # cmd.exeの場合
setx 環境変数名=値 # powershellの場合

として設定可能だ。

 Win32では、環境変数名は、「=」以外の文字ならば2バイト文字も指定できる。変数名として大文字小文字は区別されないため、「EnvVar」と「ENVVAR」、「envvar」は同一の環境変数と見なされる。ただし、変数名の大文字小文字の表記は、ファイルなどと同じく最初の指定が保存される。これは、環境変数を消去するまで保存される。

 変数値は文字列として格納される。変数値の最大サイズは32767文字まで(2バイトのUnicodeとなるため64キロバイト以下)だが、Windowsのコマンドラインや設定コマンドでの制限もあるため、常に最大サイズの変数値を指定できるとは限らない。

 環境変数を参照する場合、環境変数名を「%」で挟んで、

echo %ENV%

とする。ただし、変数を確認するだけなら、「set 環境変数名」とすれば、指定した環境変数を表示できる。また、引数無しでsetコマンドを使えばすべての環境変数を表示する。

 これに対してLinuxの環境変数は、シェル変数を「export」して設定する。シェル変数とは、シェルスクリプト(プログラム)内で利用する変数である。このため環境変数の変数名や内容に関しては、シェル変数に従う。環境変数名は、英数字とアンダースコア(アンダーライン)のみで先頭の文字はアンダースコアまたは英字である。アンダースコア以外の記号は一切使用できず、英字の大文字小文字は区別され、別の変数名として扱われる。

 環境変数を定義するには、exportコマンドを使い

export シェル変数名=変数内容
export すでに定義してあるシェル変数名

とする。参照する場合には、

echo $シェル変数名
echo

とする。後者は、後続する文字などと区別する場合に使うが単独でシェル変数を参照する場合には前者の表記でも問題ない。また、Windowsのsetコマンドに相当するのは、「printenv」コマンドである。bash内ではsetコマンドは、シェル変数の一覧となっており、大量の表示が出るので注意されたい。

 WindowsとLinuxの環境変数の違いから、RS4の環境変数共有機能では、アンダースコア以外の記号は使わないようにし、Linux側の環境変数に合わせ、環境変数名はASCIIコードの英数字で大文字で指定するのがいいだろう。

 アンダースコア以外の記号がある環境変数名はWSLENVで指定しても共有できない。基本的にLinuxは小文字文化なので、プログラミングに利用するシェル変数には小文字を使い、環境変数名には、大文字を使うことが多い(ただし、あくまでも慣習である)。

 Linux環境ではシェル変数(および環境変数)を大量に使い、多くのコマンドが環境変数による実行の制御を行なっている。また、シェル自体が予約のシェル変数を持ち、システム自体にも予約の環境変数名がある。WSLで使われるLinuxディストリビューションであるUbuntuやSUSEではbashが使われているので、「man bash」コマンドやインターネット検索で予約のシェル変数などを調べることができる。

 これに対してWin32側は大文字小文字を区別しないのでどちらでも同じである。環境変数名の英字を大文字のみにすることでことで、Linuxのシェル変数とWin32で利用する環境変数名が衝突する可能性を低くできる。

環境変数の共有設定

 RS4に搭載された環境変数のWin32とWSLの環境変数の共有機能は、共有したい環境変数名を「WSLENV」という環境変数に「:」(コロン)で区切って指定するというものだ(Win32側でもコロンで区切る点に注意)。

 このとき、各環境変数名にはパスなどの変換を指定するオプション(以下の表)を付けることができる。これにより、起動前の環境で環境変数の中身を指定し、起動された環境でそれを利用することが可能になる。

オプション 意味
/p 単独パスの変換
/l パスリストの変換
/u パスの変換をせずに共有
/w Win32相互運用性に渡さない環境変数※

※:WSLを起動する前のWin32側で指定した場合のみ有効

 このとき、drvfs上のファイルパスに関しては、変換を指定することができる。オプション/pは、環境変数の値が単独のパスであり、これを変換して共有することを意味する。つまり、「c:\~」と「/mnt/c/~」のdrvfsのパスを変換する。

 これに対して「/l」は変換の対象となる環境変数の値が複数のパスを記述したリストであることを示す。パス同士は、Win32側ではセミコロンで、WSL側ではコロンで区切る。PATH環境変数のような複数のパスを含む場合に指定する。なお、変換できるのは、ファイルのパスのみでワイルドカードを含む場合、エラーとなり共有されない。

 /uと/wは、それぞれWSL環境、Win32環境でのみ共有を行う環境変数を指定するものとマイクロソフトのブログには記載がある(https://blogs.msdn.microsoft.com/commandline/2017/12/22/share-environment-vars-between-wsl-and-windows/)。

 WSLENVで/uが指定された環境変数は、Win32からWSLを起動したときのみ共有され、/wは、逆でWSLからWin32を起動したときのみ共有が行われると記述されている。だが、環境変数の振る舞いはちょっと複雑なのでこのオプションの挙動もちょっと複雑である。WSLからWin32相互運用性を使って起動されたWin32では、環境変数は、Win32起動セッションのものを継承する。この挙動は、RS3でもRS4でも同じだ。

WSLから起動されたWin32環境は、WSLを起動したWin32の環境を引き継いでいる

 まず、Win32→WSLの場合、/wを指定した環境変数は、WSL側では共有されない。そもそも、WSLは、PATH以外の環境変数を共有しないので/wは無意味に見える。だが、Win32相互運用性でWin32環境を起動すると、/wを指定した環境変数は継承されない。つまり、「/w」は、Win32相互運用性でプログラムに対して見せたくない起動セッションで定義されている環境変数を指定するものといえる。

 これに対して/uは、Win32起動セッションからWSLを起動した場合のみ共有する環境変数を指定するものだが、意味としては「環境変数の共有を行うがパスの変換は行わずにWSLと共有する」だ。/pや/lは、パスを変換してしまうが、/uは変換しないで環境変数を共有する場合に使う。なお、Win32相互運用性では、Win32起動セッションの環境変数(WSLENVで/wが指定されているものを除く)を継承しているので、/uを指定した環境変数は、そのまま有効だ。

 実際の動作を試してみたのが下の画面だ。

3つのスクリプト(Batchとbash)で環境変数共有(WSLENV)の挙動を確かめてみた

 この例では、DIRコマンドのオプションを指定するDIRCMD環境変数をWin32相互運用側に見せないように/wで指定している。なお、理由は不明だが、WSL側でWSLENVを変更する場合、exportコマンドによる変更はうまく動作せず、実行コマンドの前にWSLENVへの代入文を置く必要がある。この構文は、bashでの環境変数の一時的な変更とコマンドの実行の形式である。このデモではFILEPという環境変数をWSLENVに追加している。

 Win32相互運用性で起動されたcmd.exeでは、DIRCMD環境変数は設定されておらず、最後に実行したDIRコマンドの結果は、最初に行なったDIRコマンドと順番が違っている。

カテゴリートップへ

この連載の記事

注目ニュース

ASCII倶楽部

プレミアムPC試用レポート

ピックアップ

ASCII.jp RSS2.0 配信中

ASCII.jpメール デジタルMac/iPodマガジン