第1回 フォルダー内のJPEGファイルを連番でリネームする 第2回 他の画像形式をJPEG形式に変更する 第3回 ピクセルサイズに応じて画像ファイルをリサイズする 第4回 実行先のフォルダーを引数で指定する 第5回 case文でスクリプト内容を整理する
第6回Webページの情報をシェルスクリプトで取得する 第7回取得結果をCSVファイルやテキストファイルに出力する 第8回インターネットショートカットファイルを作成する 第9回散らかったデスクトップを片付ける 第10回時間軸でデスクトップを片付ける
第11回BashからExcelブックにアクセスする 第12回フォルダーの中のエクセル請求書ファイルを合計する 第13回フォルダの中のファイルを一括でPDFにするには 第14回整理整頓!空のフォルダを一括でデスクトップに移送する 第15回ファイル名ではなく内容判断で重複ファイルを削除するには?
第16回文章をMarkdown記法で整える

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パスを利用するなど制限や注意点をまとめているが、コマンドラインの操作に慣れた利用者にとって、この相互運用性の向上は大きな恩恵となるだろう。

cbwinなどのオープンソースを利用しなくとも、WSL内からWin32アプリケーションの起動が可能になった(公式ブログより抜粋)

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」を使うと正しく変換されることが多い。

「メモ帳」で開いているため改行がおかしくなっている様に見えるが、UTF-8+LFで出力されるため、対応するテキストエディターを使えば問題なく扱える

オプション「-htmlmeta」を使用した状態。この他にもエンコードを指定する「-enc」などいくつかの変換オプションが用意されている

このように簡単な操作で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コマンドが対応しているか確認するとよい。

こちらは元となる「Input」フォルダー(ディレクトリ)。ダミーとしてExcelワークシートファイルなども含めた

シェルスクリプトを実行すると、「Output」フォルダー(ディレクトリ)にテキストファイルを出力する

阿久津良和(Cactus)