Bashを任意の場所で開く

BUW(Bash on Ubuntu on Windows)を使用する場合、通常はLinuxのホームディレクトリとなる「%LOCALAPPDATA%\lxss\home{ユーザー名}」フォルダーが開く。だが、任意のフォルダーで使用したいという場面は少なくない。findstrコマンドよりもgrepコマンドで文字列にマッチする行を抽出したい場合、現在のフォルダーからBashを起動できれば便利だろう。この問題はレジストリを操作すれば、簡単に解決できる。少々煩雑になるが、以下にその手順を紹介しよう。

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

レジストリエディターが起動したら、HKEY_CLASSES_ROOT\Directory\Background\shellキーを開く

shellキーを右クリックし、<新規>→<キー>と順にクリックする

キー名を「新しいキー #1」から「Bash」に変更する

Bashキーの「(既定)」をダブルクリックし、データを「Open Bash」に変更したら<OK>ボタンをクリックする

続けて右ペインの何もないところを右クリックし、<新規>→<文字列>と順にクリックする

値名を「新しい値 #1」から「Extended」に変更する

Bashキーを右クリックし、<新規>→<キー>と順にクリックする

キー名を「新しいキー #1」から「command」に変更する

「(既定)」をダブルクリックで開き、データを「cmd.exe /c pushd \"%V\" && bash.exe」にしたら<OK>ボタンをクリックする

一連の操作を、HKEY_CLASSES_ROOT\Directory\shell\Bash\commandキーに対して実行する

以上で操作は終了だ。Bashを起動したいフォルダーやデスクトップの何もないところを[Shift]キーを押しながら右クリックすると、コンテキストメニューに<Open Bash>が加わったことを確認できるだろう。こちらをクリックすれば、Bashが起動する。具体的にはcmd.exe=コマンドプロンプトを起動し、pushdコマンドでカレントフォルダーを移動。その結果が正常に終了した場合に、bash.exeを起動する仕組みだ。今回は文字列値「Extended」を追加することで、[Shift]キーを押した時でないと項目が現れない設定を施しているが、常に表示させる場合は文字列値「Extended」は追加しない。

デスクトップの何もないところやフォルダーを、[Shift]キーを押しながら右クリックすると、<Open Bash>が加わる

<Open Bash>をクリックすると、カレントフォルダーに移動した状態でBashが起動する

なお、追加したレジストリエントリーを削除すれば、コンテキストメニューの項目は消えるが、面倒な場合は下記囲みの内容を、テキストエディターで下記囲みの内容を入力し、ファイル名の拡張子に「.reg」を付けてからUTF-16(BOM付き)で保存。作成したレジストリファイルをダブルクリックすれば、各エントリーを数ステップで削除できる。

Windows Registry Editor Version 5.00
[-HKEY_CLASSES_ROOT\Directory\Background\shell\Bash]
[-HKEY_CLASSES_ROOT\Directory\shell\Bash]
[-HKEY_CLASSES_ROOT\Drive\shell\Bash]
[-HKEY_CLASSES_ROOT\LibraryFolder\Background\shell\Bash]

BashからExcelブックにアクセスする

さて、今回は新しいシェルスクリプトにチャレンジしよう。日常業務でExcelを使う機会は多いと思うが、Excelブック(ワークシート)の実体はZIP形式ファイルであることをご存じだろうか。以前はバイナリ形式だったものの、Excel 2007からXMLベースに切り換え、関連ファイルをZIPでパッケージングしたファイル形式に切り替わっている。unzipコマンドをインストールし、展開するといくつかのフォルダーとファイルが展開されるはずだ。フォルダーをたどっていくと「xl\worksheets」フォルダーに「sheet1.xml」「shhet2.xml」……と、Excelブックのワークシートと同じファイル名が確認できる。だが、こちらはセルなどの設定内容であり、セルに入力した数値や文字列は含まれていない。

「unzip」は既定のパッケージに含まれいないので、「sudo apt-get install unzip」を実行してインストールする

「unzip {ファイル名}.xlsx」と実行すると、Excelブックの内容が展開される

すべてのバージョンで確認した訳ではないが、Excel 2016で作成したExcelデータの場合、数値や文字列は「xl\sharedStrings.xml」に含まれている。基本的には改行を含まないXML形式ファイルだが、セル内の文字列に「&」含まれると、エンティティ参照(XML上でダブルクォーテーションなどを扱うエスケープ文字)が加わり、「&」が置き換わる部分のみ改行が加わる仕組みだ。

sharedStrings.xmlsの内容を表示させた状態。セル内に入力した文字列が記録されている

ちなみにこちらが元となるExcelブック。特に内容は気にしないでほしい

それではここから文字列を抜き出してみよう。今回はsedではなく、改行について柔軟に対応できるperlを利用したシェルスクリプトを作成した。いつもどおりvimなどで下記の内容を作成し、chmodコマンドで実行権限を付加してほしい。

 #!/bin/bash

 BaseDir=/mnt/c/Users/kaz/Desktop
 BaseFile=$BaseDir/Book1.xlsx
 TmpDir=/tmp/_TMP
 OutputFile=$BaseDir/Output.txt

 if [ ! -d $TmpDir ]; then
    mkdir $TmpDir
 fi

 unzip -qq $BaseFile -d $TmpDir
 cat $TmpDir/xl/sharedStrings.xml | perl -pe 's/\&amp;/&/g; s/></>\n</g; s/[\n|\r]//g; s/></>\n</g; s/<[^>]*>//g' | perl -pe 's/^\n//g' > $OutputFile
 rm -rf $TmpDir

perlのオプションとしてスクリプトを実行する「e」と結果を標準出力する「p」を組み合わせ、正規表現を用いてワンライナーで行っている。ただし、改行が正しく削除されなかったので、パイプを経由して再びperlで削除した。このスクリプトを実行すると、変数「BaseFile」で指定したExcelブックから文字列だけを変数「OutputFile」で定義しているテキストファイルに出力する。

シェルスクリプトを実行するとセルの文字列をテキストファイルに出力できる

もちろんExcel本体を使えばタブやカンマで区切ったCSVファイルを出力できるため、このようなシェルスクリプトを用いる場面は少ないだろう。だが、実行するだけでファイル展開から文字列の抜き出し、後処理(展開ファイルの削除)までのワンストップで実行できる点は、シェルスクリプトならではだ。

阿久津良和(Cactus)