連載
» 2019年04月05日 05時00分 公開

ITの教室:【WSL入門】第2回 避けては通れないWSLとWindows 10との文字コードの違い

WSLを活用するためには、Windows OSとWSLの関係を理解するのが第一歩。基本となるWindows 10とWSLの文字コードの違いなどを理解しよう。

[塩田紳二,著]

ITの教室 WSL入門」では、WSLを活用するための基礎をインストールから解説していく。



 Windows 10の中で、Linuxを動作させるWindows Subsystem for Linux(WSL)では、フル機能のコマンドやコマンドインタープリター(シェル)を利用でき、高度なコマンドライン機能を持つ(WSLのインストール方法については、「第1回 Windows 10標準Linux環境WSLを始めよう」参照のこと)。

 WSLにUbuntuをインストールしたら、マニュアルの日本語化などを行おう。

WSLの基本設定 「パッケージのインストール」と「日本語対応」

 Linux/UNIXでは、基本的な利用方法は、オンラインマニュアルをmanコマンドで検索して行う。コマンド名が分かっているなら、「man bash」などのようにmanコマンドに引数としてコマンド名を付けて実行する。

 コマンド名が分からない場合には、キーワード検索を行う。例えば、「man -k editor」という感じだ。実際の使い方についてはmanコマンドのオンラインマニュアルを見てほしい。

パッケージのアップデートを実行しよう

 WSL用にMicrosoft StoreからUbuntuをインストールしただけの状態では、オンラインマニュアルは全て英語のままになっている。これは、標準状態が英語のままだからだ(正確にはCロケールという状態)。全てではないが、オンラインマニュアルには日本語化されているものもあるので、これをインストールしよう。

 一般にUbuntuでは、aptコマンドを使ってパッケージのインストールを行う。Ubuntu用のパッケージなどが公開されているサイトを「リポジトリ」といい、aptコマンドはリポジトリの情報を持っているため、最新のパッケージをダウンロードして組み込むことができる。パッケージのインストールに関しては、別途機会を改めて解説するので、今回は、こんなコマンドを使うということだけ理解してほしい。まずは、リポジトリからパッケージ情報をダウンロードしてローカルのデータベースを最新にしておく。

sudo apt update

Ubuntuを最新のパッケージにするコマンド

 sudoは、管理者権限でコマンドを実行するためのものだ。これを付けないと管理者権限が必要なコマンドを実行できない。また、管理者のパスワード(Ubuntuを最初に実行したときに登録したパスワード)を聞いてくる。

 このコマンドを実行すると“XXX packages can be upgraded. Run 'apt list --upgradable' to see them.”や「アップグレードできるパッケージが xxx 個あります。……」(日本語化している場合)といったメッセージが最後に表示されることが少なくない。これは、インストールされているパッケージの中に更新されたものがあることを示す。古いものはセキュリティ的な問題が出る可能性があるので、なるべくアップグレードしておこう。

 Windows OSと違って、Linux系のパッケージシステムは、パッケージ同士の依存関係を把握しているため、何かをアップグレードしたからといってほかのアプリがおかしくなることはほとんどない。もちろん、人のやることなので、アップグレードしたプログラム内で新たなバグが発生することはあるが、他のパッケージやUbuntu自体までにアップグレードの影響が及ぶことは少ない。

 更新されたパッケージをまとめてアップグレードするには、「sudo apt upgrade」を実行する。取りあえず、「apt update」と「apt upgrade」は組にして覚えておいた方がいいだろう。

 その後、日本語化を行う。詳細なやり方は、Tech TIPS「WSLのUbuntu環境を日本語化する」を参考にしていただきたいが、以下のコマンドを実行する。

sudo apt -y install language-pack-ja
sudo update-locale LANG=ja_JP.UTF8
sudo apt -y install manpages-ja manpages-ja-dev

Ubuntuを日本語化するコマンド

 それぞれ、日本語パッケージ(language-pack-ja)のインストール、ロケール情報の更新、日本語マニュアルページ(manpages-jaとmanpages-ja-dev)のインストールである。なお、Window 10 October 2018 Update以降のWSLは、何もしなくてもタイムゾーンを正しく認識しているようなので、タイムゾーン設定は不要である。

 最後に、WSLを一回終了させる(WSLで全てのウィンドウを閉じる。なお、バックグラウンドプロセスを起動したなら止めておく)。これで、再度WSLのウィンドウを開けば、ロケールが「ja_JP.UTF-8」になっているはずである。これは、localeコマンドで確認できる。

localeコマンドを実行結果 localeコマンドを実行結果
現在のロケールは、localeコマンドで表示できる。

日本語化でマニュアルの日本語による検索も可能に

 WSL上での日本語の入力だが、WSLが動作しているWindows 10のコンソールは、Windows OS側の日本語IME経由での入力が可能なので、特にWSL側にIMEを入れる必要はないと思われる。

 日本語マニュアルがインストールされたため、bashのマニュアルなどは日本語で表示されるはずである。また、-kオプションによるキーワード検索でも、「man -k シェル」などといった日本語キーワードによる指定が可能になる。

 なお、日本語のマニュアルは、英語のマニュアルからの翻訳であるため、タイミングによっては、内容が古くなっている可能性がある。マニュアルとコマンドの挙動が違うような場合、英語マニュアルを参照する必要が出てくる。

 このようなときには、「env LANG=C man コマンド名」などとして、$LANGを一時的にCロケールにしてmanを実行させるとよい。envは環境変数を指定してコマンドを起動するものである。詳しくはmanで調べてほしい。とにかく、Linux/UNIX系は、知りたいことがある場合には、manコマンドを使うというのが定石だ。細かいオプションなどについては解説できないので、より詳しく知りたい場合はmanコマンドでマニュアルを参照してほしい。

 WSLのUbuntuディストリビューションでは、manコマンドの中で検索が利用できる。それには「/」を入力して検索語を入れる。日本語化してあれば、もちろん日本語でも検索が可能だ。

 検索語は、manページ中では反転表示(コンソールの設定にも依存する)となり、「n」で次の検索語位置に進み、「N」で前に戻る。これらの操作は、実際には、lessと呼ばれるプログラムの機能だ。manコマンドは、lessやmoreといったページャープログラムを利用してページを表示している。

WSLの中からWin32コマンドを使う

 WSLには、Win32相互運用性と呼ばれる機能があり、Windows OS側のコマンドを起動し、Windows OSのファイルシステムへのアクセスが可能だ。このため、WSLのシェルであるbashから、Windows OSのコマンドラインとほぼ同じようなことができる。

 例えば、実行コマンドのファイルがある場所を示すPath環境変数だが、Windows 10になってようやくGUI形式の編集機能が実装された(TIPS「Windows 10でPath環境変数を設定/編集する」参照)。しかし、相変わらずコマンドラインで作業する場合には、全部がつながったPathの設定値を表示することしかできない。

 これに対してWSLでは、trコマンドを使ってパスを区切っているセミコロンを改行コードに置き換えることができ、パスを1行1つに表示させることが可能だ。

Ubuntuのtrコマンドを使ってパス環境変数を表示させてみる Ubuntuのtrコマンドを使ってパス環境変数を表示させてみる
Windowsのコマンドラインでは、つながったパス環境変数の設定値しか見ることができなかったが、WSLからだとtrコマンドでセミコロンを改行に置き換えて個々のパスに分けて見ることができるようになった。

 Linuxのコマンドには、こうしたちょっとした便利な機能を持つものが少なくない。多少でもコマンドラインで作業をすることがあるなら、WSLを使うことをお勧めする。cmd.exeとの違いは、Win32コマンドを実行する際にファイル名の拡張子(.exe/.com/.bat)を省略しないことぐらいだ。

 なお、この連載では、WSL側のLinuxとWindows OS側の両方の記述をするが、両者に同じ名前のコマンドがある。そのため、Windows OS側のコマンドを表す場合には、必ず拡張子を付けて記述する。例えば、「コマンドラインの並べ替え機能はsort.exeなど」と記述する。逆に拡張子の付かないコマンドは、Linux側のコマンドである。sortとだけ表記すれば、それは、Linuxのsortコマンドとなる。

 原則、UNIX/Linux系では、コマンドの実行ファイル名は小文字である。また、Windows OS側を「Win32側」と表記することがある。これはWSLに対して、従来のWindows OS側は「Win32 Subsystem」と呼ばれていたためだ。そこで、WSLからWindows側を見たときに「Win32」側と呼んで区別する。

 その他、コマンドラインを記述する場合、先頭部分が「$」で始まるものは、WSL側のコマンドライン(このときコマンドの拡張子が入らないことがある点に注意されたい)で、「>」で始まるものは、Win32側のコマンドラインとさせていただく。これは、それぞれのコマンドラインインタープリター(bashとcmd.exe)の標準のプロンプトに由来する。

 例えば、「$ dir | sort」とした場合はWSL側のコマンドラインを表し、「> dir | sort.exe」の場合には、Win32側のコマンドラインを表す。

 WSLとコマンドラインとの相互呼び出しについては、以下の記事も参照していただきたい。

WSLとWin32の文字コード

 Linuxでは、「ロケール(locale)」により標準として使う文字コードを指定する。現在のLinuxでは標準的にUnicodeUTF-8エンコードで使うようになっている。これに対して、日本語のWindows 10のコマンドは、現在のコードページに従って文字コードを切り替える。コードページは、Windows OSのコンソールで入出力に使う文字コードとフォントセットを指定するものだ。もし日本語のコードページである「932」が使われていれば、文字コードとしてShift-JISコードが使われる。

 話を簡単にするため、ここではWin32相互運用性を使い、WSLからWin32アプリケーションを起動したときについてのみ考えることにする。このときの動作は以下の2つに分かれる。

  • Win32側のコマンドの標準出力が何も接続されておらず、コンソールに出力が行われる場合
  • パイプやリダイレクションなどでWin32アプリの標準出力を他のプロセスが受け取ったり、ファイルとなったりするような場合。これには、WSL側でリダイレクトを行わせる場合と、Win32側でリダイレクトを行う場合の2通りがあり得る

 WSL側でリダイレクションやパイプ処理が行われない場合、Win32コマンドは、Windows OSの通常環境と同じくコードページ932(デフォルトのコードページ)で動作し、日本語を含む出力が行われる。これに対して、bashがリダイレクトやパイプを処理する場合、Win32アプリケーションは、コードページ65001(UTF-8)の環境で動作することになる。この切り替えはWSLが自動的に行う。

 コードページが65001のとき、標準アプリの多くは、メッセージなどが全て英語となる(実際にはコマンド依存)。例えば、コードページ932では、dirコマンドの出力の冒頭部分には、「ドライブ C のボリューム ラベルがありません。」といった日本語のメッセージが表示されるが、コードページ65001では、「Volume in drive C has no label.」という出力に切り替わる。しかし、ファイルのリストでは、日本語のファイル名などがある場合にファイル名はUTF-8で表現される。

コードページが932の場合のdirコマンド出力 コードページが932の場合のdirコマンド出力
冒頭部分が日本語のメッセージで表示される。また日本語のファイル名やフォルダ名もShift-JISで出力される。

コードページが65001の場合のdirコマンド出力 コードページが65001の場合のdirコマンド出力
冒頭部分が英語のメッセージで表示される。日本語のファイル名やフォルダ名は、UTF-8で出力される。

 リダイレクトやパイプ処理などを行う場合には、Win32側かWSL側(bash側)のどちらがパイプ記号、リダイレクト記号を解釈するかという問題がある。

 例えば、「cmd.exe /c 'dir >test.txt'」とすれば、Win32側でリダイレクトが行われる(/c以下が全てシングルクオートで囲まれていて、bashがこの中を解釈しないという点に注意)。しかし、「cmd.exe /c dir >test.txt」とすれば、WSL側でリダイレクトが行われる。

 前者は、WSL側からみると単一のコマンドでリダイレクトが行われていないように見えるため、cmd.exeは、コードページ932で動作し、後者は、リダイレクトを処理するのはbashになるため、cmd.exeは、コードページ65001で動作する。このとき、カレントディレクトリに日本語を含むファイルなどがあった場合、前者はShift-JISコードでファイル名リストが出力され、test.txtに入る。これに対して後者ではUTF-8となり、test.txtにはUTF-8が入る。この辺りをまとめたのが下図だ。

コードページとWSL/Win32コマンドの関係 コードページとWSL/Win32コマンドの関係

コードページによる違いに注意

 Win32相互運用性によるWin32コマンドとLinuxコマンドをパイプでつなぐと、Win32側の標準出力には、UTF-8コードが出るため、以後のLinuxコマンドの処理で問題が出ることは「原則」ない。そこで、コマンドを組み合わせて使っているときには、文字コードの違いについては原則考える必要はない。

 しかし、Windows OSのコンソールコマンドの中には、コードページが65001であっても、Shift-JISコードを出力してしまうプログラムが存在している点に注意が必要だ。

 サービスを制御するsc.exeコマンドは、先頭のヘッダ部分などは、コードページに応じて日本語と英語が切り替わるのだが、サービスの表示名や詳細などはShift-JISコードがそのまま出力されることがある(インストールされているサービスに依存する)。

 また、sort.exeもコードページが65001であっても、出力はShift-JISになってしまう。ただしWSL側には、こうしたWin32の標準コマンドの大半を置き換えるだけでなく、より強力なコマンドが用意されている。おそらく、どうしても実行させる必要のあるWin32コマンドは、tasklist.exeやWindows OSのシステム関連の情報を出力するようなものに限られるはずだ。

 もう一つ注意が必要なるのは、コマンドにファイルパスを指定してファイルの読み書きを行わせる場合だ。日本語版Windows 10では、Shift-JISコードが標準であるため、Win32側のファイルには、Shift-JISコードが含まれている可能性が高い。

 これに対してLinux側の文字コードは、UTF-8なので、Linux側にある、あるいはLinuxコマンドで出力したファイルには、UTF-8コードが含まれている可能性が高い。ただし、いわゆるASCIIコードの範囲であれば、両者は一致しているため問題はない。日本語が含まれていると、文字コードの違いが問題になる。

コードページの問題の多くはファイルをコマンドで扱う場合

 問題の多くは、ファイルをコマンドで扱う場合にある。Windows OS側もUTF-8に対する対応が進んでおり、利用が想定される「メモ帳」などは、UTF-8やLinuxの行末コードなどに対応している。しかし、全てのWindowsプログラムがUTF-8やLinuxの行末コードに対応しているわけではない。

 Linux側のプログラムは、ロケール設定に従って動作し、標準状態では文字コードはUTF-8で、行末コードは「LF」のみとなる。Linuxの多くのコマンドはシンプルな出力なので、Win32のコマンドのように出力の前にフィールドの説明などが日本語で付くことはほとんどない。

 しかし、入力に関しては、UTF-8であることを想定しているので、Shift-JISのファイルを扱うときには、文字コード変換を行う必要がある。

文字コードの変換にはnkfコマンドを使う

 Ubuntuには、標準でiconvという文字コード変換コマンドがあるが、文字コードの自動判定などの機能を持つnkfを入れて置くと便利だ。インストールは、以下のコマンドで行える。

sudo apt install nkf

nkfコマンドをインストールするコマンド

 文字コードが不明な場合、「nkf -g」を使って判定させることができるなど便利な機能がある。例えば、ファイル「/mnt/c/temp/test-ascii.txt」を調べたいのであれば、以下のコマンドを実行する。

nkf -g /mnt/c/temp/test-ascii.txt

指定したファイルの文字コードを調べるコマンド

nkfコマンドによる文字コードの推測 nkfコマンドによる文字コードの推測
nkfは、文字コードの変換だけでなく、文字コードの推測が可能だ。

 なお、Linuxにはファイルを調査するためのfileコマンドがあり、UTF-8のテキストファイルなどは「UTF-8」だと教えてくれるものの、Shift-JISの場合には「Non-ISO extended-ASCII text」などとしか表示してくれない(ASCIIコードのみの場合にはASCII textと表示はしてくれる)。

 また、fileコマンドは引数のファイルしか受け付けないが、nkfは標準入力を受け付ける(そもそもパイプ用に作られたコマンド)ためパイプでコマンドの出力をつなぐことができる。nkfコマンドは、WSLでテキストファイル文字コードを調べるのには最適といえる。ただし、文字コード定義から理論上完全判定が困難であるため、nkfコマンドの推測は間違う可能性もあることには注意してほしい。

 Shift-JISのWindows OSのテキストコード(改行コードはCR+LF)をUTF-8のLinuxテキストファイル(改行コードはLFのみ)にする場合には、「nkf -w -d」として使う。UTF-8からShift-JISと逆もできるが、おそらくほとんど利用することはないはずだ。また、入力がShift-JISであることを確実にするには「-s」オプションを付けておく。


 次回は、bashのヒストリーなどの便利な機能やWSLとWin32の関係などを紹介する。

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。