Windows 10 Anniversary UpdateからサポートしたWindows Subsystem for Linux(WSL)。その結果としてWindows 10上でもBashを始めとするLinuxコマンドが利用可能になった。本連載ではWSLに関する情報や、Bashから実行するシェルスクリプトを紹介する。
Ubuntu 16.04のサポートとWindows/WSLの相互運用
Microsoftは2016年10月19日(現地時間)にWindows 10 Insider Preview ビルド14951をリリースしているが、同OSビルドから、Ubuntu 16.04(Xenial)を公式サポートするようになった。執筆時点ではWindows Insider Programに参加している筆者の環境にOSビルド14951が配信されないため動作検証に至っていないが、以前の記事で述べたように自動アップグレード機能は用意されていないため、「do-release-upgrade」コマンドを使用するようだ。
もう1つの改善点がWindowsとWSL(Windows Subsystem for Linux)の相互運用サポートである。WindowsバイナリをBashのコマンドラインから直接呼び出せるという。リリースノートによれば、「export PATH=$PATH:/mnt/c/Windows/System32」と環境変数PATHの値を拡張することで、「notepad.exe」を実行すれば「メモ帳」が起動し、「ls -la | findstr.exe foo.txt」と実行すればlsコマンドの標準出力をWindowsバイナリのfindstr.exeへ渡して、"foo.txt"を含む行を出力できるようだ。
コマンドプロンプト上で動作しているが、bash.exe経由でlsコマンドを呼び出し、その結果をfindstr.exeでマッチ行を抽出。もちろんdirコマンドの結果をgrepコマンドで抽出するという逆の操作も行える(公式ブログより抜粋) |
このロジックはMicrosoft公式ブログの「Windows Subsystem for Linux」に投稿された記事が詳しい。Microsoftの開発陣はBash.exeとcmd.exeという2つのシェル同士の入出力をリダイレクトするため、WSLの改良に勤しんだという。この辺りの詳細は既報のため本稿では割愛するが、WSL内からWin32アプリケーションの起動もできるのは興味深い。Microsoftは本連載でも過去に紹介したcbwinを取り上げつつ、binfmt_miscに「sudo echo ":WSLInterop:M::MZ::/init:" > /proc/sys/fs/binfmt_misc/register」と登録することで、Win32アプリケーションの起動を実現しているという。
「WSLInterop」はユニークな登録名として存在し、「M」はマジックバイト配列もしくは拡張子を登録の種類として指定。「MZ」はWindows PEイメージのマジックバイトシーケンス。「/init」はインタープリターのフルパスを指定する。これにより、MicrosoftはBash上から環境設定PATHを事前に変更しつつも、wgetコマンドで取得したHTMLファイルを「メモ帳」で開く画像を公開している。公式ブログの記事では、Windows 10とBashが使用す環境変数は異なる存在であり、DrvFSパスを利用するなど制限や注意点をまとめているが、コマンドラインの操作に慣れた利用者にとって、この相互運用性の向上は大きな恩恵となるだろう。
PDFファイルからテキストファイルを出力する
さて、我々はPDFを日常的な電子文書形式として利用しているが、そこからテキストを抜き出したい場面に出くわすことがある。もちろん単文であればそのままコピー&ペーストすれば済む話だが、長文となるとその作業も繁雑だ。PDFを編集可能なアプリケーションを所有している場合、テキスト形式としてエクスポートする手段も残されているが、わざわざアプリケーションをインストールするのも面倒である。その場合は、LinuxディストリビューションではポピュラーなPDF描画ライブラリである「Poppler」の利用をお勧めしたい。
先のリンクURLからも分かるようにfreedesktop.orgが開発するPopplerだが、ubuntuから簡単にインストールできる。「sudo apt-get install poppler-utils -y」と実行してパッケージをBUW(Bash on Ubuntu on Windows)に展開しよう。するといくつかのコマンドが使用可能になるが、今回必要になるのはテキスト形式に変換する「pdftotext」コマンド。入力ファイルとしてPDFを、出力ファイルとして任意のテキストファイル名を引数として実行すれば、何の苦もなくテキストファイルが生成される。オプション「-htmlmeta」を使えばシンプルなHTMLファイルを生成することも可能だ。筆者は今回試していないが縦書きの日本語などが含まれる場合、オプション「-raw」を使うと正しく変換されることが多い。
このように簡単な操作でPDFからテキストファイルの生成は簡単に実行できるが、ポイントはどのようなシチュエーションで利用するか、である。今回はシンプルにシェルスクリプト内で指定したディレクトリ(フォルダー)にあるPDFファイルを順番に変換する内容にした。いつもどおりお使いの環境に合わせて変数の値を変更し、シェルスクリプトに実行権限を与えてからお試し頂きたい。
#!/bin/bash
IFS=$'\n'
BaseDir=/mnt/c/Users/kaz/Desktop
InputDir=$BaseDir/Input
OutputDir=$BaseDir/Output
if [ ! -d $OutputDir ]; then
mkdir $OutputDir
fi
cd $InputDir
for File in *; do
case ${File##*.} in
pdf|PDF )
echo "Convert the PDF:" ${File}
pdftotext -q ${File} ${OutputDir}/${File}.txt ;;
*) ;;
esac
done
今回は過去の連載で扱ってきた手法を用いている。例えば14~19行目のcase分は大文字小文字の違いを取り除くための手法であり、「for File in $(ls *.pdf)~」と記述しなかったのは、空白を含むファイル名があった場合、この方法ではエラーが発生してしまうからだ。そのため3行目に「IFS」を追加している。こちらについては今後連載で紹介しよう。なお、PDFからテキストファイルに変換できない場合、「pdfinfo」コマンドでPDFファイルの内容を確認し、pdftotextコマンドが対応しているか確認するとよい。
阿久津良和(Cactus)