Windows 10で始めるBash

Windows 10からBUWのフォルダー(ディレクトリ)へアクセスする

本稿を執筆している時点でBUW(Bash on Ubuntu on Windows)はベータ版であり、2016年8月2日リリース予定のAnniversary Updateで正式版になる保証もない。Windows 10 Insider Preview ビルド14316からサポートが始まったBUWは、当初rootでBashを起動していたが、いつのビルドからかBUWを新たに有効にする環境では、useraddコマンドが動作し、BUW上で使用するユーザーの作成が可能になった。

そのため、早期からBUWを試している方の中には、rootアカウントをそのまま使っている方も少なくない。この問題を解決するには、Windows 10がBUWを制御するために用意した「lxrun」コマンドを使用する。lxrunコマンドはBUWのインストールやアンインストール、パッケージの更新、ユーザーの追加が可能だ。

[Win]+[X]キー→[A]キーと順に押すか、スタートボタンを右クリックし、<コマンドプロンプト(管理者)>をクリックする

プロンプトに「lxrun --help」と入力して[Enter]キーを押すと、同コマンドのオプションが確認できる

具体的には上図のように管理者権限でコマンドプロンプトを起動し、プロンプトに「lxrun /setdefaultuser {ユーザー名}」と実行すればよい。BUWで使用するパスワードの入力を求められるので、2回入力すれば設定完了だ。この時点でBUWのウィンドウは自動的に閉じるので、BUWを再起動すると、指定したユーザーでBashが起動することを確認できる。

プロンプトに「lxrun /setdefaultuser {ユーザー名}」と入力して[Enter]キーを押す。パスワードの入力を求められたら、適切なパスワードを入力して[Enter]キーを押し、再び同じパスワードを入力して[Enter]キーを押す

プロンプトに表示されるユーザー名が「kaz」に置き換わっていることが確認できる

[Win]+[R]キーを押して「ファイル名を指定して実行」を起動し、テキストボックスに「%LOCALAPPDATA%\lxss」と入力して<OK>ボタンをクリックする

これでWSLのルートフォルダーが開き、ホームディレクトリやBOWのルートディレクトリが確認できる

この場合ユーザー権限でコマンドを実行するため、「/usr/sbin」などroot権限が必要なコマンド実行できない。その際は「sudo {コマンド名}」と実行ラインの先頭に「sudo」コマンドを追加すればよい。同コマンドが参照する「/etc/sudoers」については慎重に編集することで利便性が向上するが、そちらは別の機会に回し、今回はWindows 10から見るBUWのフォルダーについて紹介しよう。

WSL(Windows Subsystem for Linux)のルートフォルダーは「%LOCALAPPDATA%\lxss」である。BUWを起動して表示するルートフォルダーは「%LOCALAPPDATA%\lxss\rootfs」だが、lxssフォルダーには「home」や「root」といったユーザーディレクトリが並ぶ。コマンドプロンプトから確認してみたが、ジャンクションやシンボリックリンクではないようだ。

例えばBUW上でディレクトリを作成すると、「%LOCALAPPDATA%\lxss\home\kaz」以外に「%LOCALAPPDATA%\lxss\rootfs\home\kaz」も同じフォルダーが存在する。ロジックに関してはWSLファイルシステムに関する説明が必要なので今回は割愛するが、Windows 10上で動作するテキストエディターでスクリプトを編集する場合は、前述したフォルダーを参照すると、vimやEmacsといったUNIX系テキストエディターに慣れていない方には便利だろう。

実行先のフォルダーを引数で指定する

それでは今回のシェルスクリプトを紹介しよう。前回までは画像ファイルの数字連番でリネームするシェルスクリプトを書いてきたが、これまでは対象となるディレクトリ(フォルダー)を変数で固定していた。そもそもシェルスクリプトには、引数というコマンドラインで与えられたパラメーターをスクリプト内に扱う機能が備わっている。

シェルスクリプトで使用可能な引数に関する主な変数

これらを用いれば、シェルスクリプト実行時にWindows 10のフォルダーを指定することで、ファイル名や画像ファイルサイズの変換が可能になり、汎用性も高まるだろう。まずはいつもどおり下記に示したシェルスクリプトをBUW上で作成し、「chmod 755」などを実行して実行可能な状態にしてほしい。

 #!/bin/bash

 Cmdname="$0"
 Number=1
 MaxSize=1200

 if [ "$#" -ne 1 ]; then
    echo "Usage: ${Cmdname} Directory" 1>&2
    exit 1
 elif [ -d $1 ]; then
    cd $1

    for OldFile in $(ls *.jpg *.png *.tif *.bmp); do
        Width=`identify -format "%w" $OldFile`
        NewFile=$(printf %03d.jpg $Number)

        if [ ${Width} -gt $MaxSize ]; then
            convert -density 72 -quality 90 -resize 1200x $OldFile $NewFile
        else
            convert -density 72 -quality 90 $OldFile $NewFile
        fi

        rm $OldFile
        echo "Convert and Rename $OldFile to $NewFile."
        Number=$((Number+1))
    done;
 else
    echo "Usage: ${Cmdname} Directory" 1>&2
    exit 1
 fi

今回加えたコードを順に説明しよう。3行目はシェルスクリプトのファイル名を示す「$0」を変数「Cmdname」に代入し、エラー処理の表示内容に用いている。次に7行目は引数の数を示す「$#」が「1」と異なる(-ne)場合、8行目のメッセージを表示し、9行目でシェルスクリプトを終了している。

10行目の「elif」は7行目から始まるif文に対して異なる場合の条件分岐を行うために用意した。「-d」は引数($1)がディレクトリである(-d)場合は真を返し、次の行を実行する。今回は変数「Dir」を使っていないため、11行目で行うディレクトリの移動は直接引数を渡すことにした。

13行目から26行目の処理は前回と変わらないため割愛し、27行目から29行目に挿入したコードは、ディレクトリを指定していない場合を想定し、前述したエラーメッセージを表示してシェルスクリプトを終了というもの。そろそろif文だらけでコードの可読性が低下してきたので、次回はこの辺りを整理してみよう。

シェルスクリプトに引数を与えない、もしくは存在しないフォルダー(ディレクトリ)を与えると、使い方を示すメッセージを出力して、スクリプトが終了する

こちらは正しくリネームおよび画像サイズの変換が行われた状態

阿久津良和(Cactus)