sironekotoroの日記

Perl で楽をしたい

Windows のバッチファイルにファイルをドラッグ&ドロップして、Perl でなんか処理する

Windows 使ってます

ということもあり、これらの Windows には Strawberry Perlストロベリー パールを入れています。

strawberryperl.com

Windows で簡単にインストールできる Perl としては Active Perl もあるんですが、Strawberry Perl は cpanm が最初からセットアップされていたりで使いやすく、気に入っています。

業務用途だと、プロダクション環境と開発環境で Perl のバージョンを合わせる必要があり Strawberry Perl だと大変なんじゃないかなー、と思うのですが・・・個人で使う分には Strawberry Perl で良いのではないかと思います。

というか、WindowsPerl 動かしてる業務環境はなかなかレアですねー。皆無とは思わないですが、実例知らない・・・

バッチファイル書いていく

Windows でも Perl 使うことができるんですが、Windows では GUI をフルに生かして使いたい!

ってことで、バッチファイルにドラッグ&ドロップしたファイルを Perl に引数として渡すってのを紹介します。

基本的なバッチファイルはこちらで、これに付け足していきます。

メモ帳(notepad.exe)で書いていきます。ちなみに、いまメモ帳のデフォルト文字コードutf8 なんすよ。

f:id:sironekotoro:20210131162043p:plain

@echo off
setlocal
cd /d %~dp0

rem %~f1 ドラッグ&ドロップされたファイルのフルパス
echo %~f1

pause

この内容で arg.bat とかいう名前で保存します。

f:id:sironekotoro:20210131132039p:plain

最初の3行はいわばバッチファイルを書くときの「お約束」ですね。3行目はバッチファイル実行時に、このバッチファイルがあるフォルダを実行場所にするためのものです。

@echo off
setlocal
cd /d %~dp0

その次の rem から始まるのがコメント行、Perl でいうと # です。

%~f1 が引数のフルパスを示すものです。

rem %~f1 ドラッグ&ドロップされたファイルのフルパス
echo %~f1

適当なファイルをこのバッチファイルにドラッグ&ドロップするとこうなります。

f:id:sironekotoro:20210131132400p:plain

キーボードの適当なキーを押すと終了します。

バッチファイルから Perl 起動して引数渡す

バッチファイルから起動する Perlスクリプトはこちらです。Hello! [コマンドライン引数] と表示するものです。

これもメモ帳で書きます。

#!/usr/bin/env perl
use strict;
use warnings;

print "Hello! @ARGV";

バッチファイルはちょっとだけ手直し。

@echo off
setlocal
cd /d %~dp0

rem ドラッグ&ドロップされたファイルのフルパスを Perl のコマンドライン引数に渡す

perl hello.pl %~f1

pause

この Perl スクリプト とバッチファイルを同じ場所に置いて、適当なファイルをバッチファイルにドラッグ&ドロップ。

f:id:sironekotoro:20210131141930p:plain

無事、Perlスクリプトにファイルのパスが渡りました。めでたしめでたし!

ドラッグ&ドロップしたテキストファイルの中身を表示すると・・・文字化け!

・・・で、終わればいいんですけどね。

今度は、ドラッグ&ドロップしたテキストファイルの中身を表示してみましょう。

テキストファイルを作ります。中身はこんな感じ。ファイル名は Perl入学式.txt

Perl入学式 2月開催をお楽しみに!

f:id:sironekotoro:20210131152252p:plain

まずはこのファイルをドラッグ&ドロップ。

はい、ちゃんとファイル名が出ましたね。

f:id:sironekotoro:20210131151454p:plain

では、ファイルの中身を表示すべく Perl 側のスクリプトを新たに作ります。ファイル名は open_text.pl とします。

素直な、ファイル開いて1行1行表示するものです。

#!/usr/bin/env perl
use strict;
use warnings;

open my $FH, '<', $ARGV[0];
for my $line(<$FH>){
    chomp $line;
    print $line . "\n";
}
close $FH;

バッチファイルも呼び出す Perlスクリプト名を変更します。

@echo off
setlocal
cd /d %~dp0

rem バッチファイルから起動するスクリプトを変更
perl open_text.pl %~f1

pause

f:id:sironekotoro:20210131152634p:plain

はい文字化けー

ということで、PerlWindows で動かすときの大きな障壁の一つがこの文字化けだと思います。

自分もかつて、ここでつまづきました。

これは、Windowsコマンドプロンプトcp932 という文字コードであることに対し、Perl で出力する際の標準の文字コードutf8 であることが原因です。

f:id:sironekotoro:20210131153529p:plain

ですので、これを正しく表示するためには

のいずれかが手取り早いです。

「郷にいれば郷に従え」で、最初の Perl文字コードを変更する方法が良いのではないかなぁと思います。

Perlスクリプト側で入出力する文字コードWindows 環境に合わせる

スクリプト中にコメントで書きましたが、Encodeエンコード モジュールを使います。

それぞれどの文字コードで読み込むのか、出力するのかを明示したものです。

#!/usr/bin/env perl
use strict;
use warnings;

use Encode;  # 文字コードを扱うモジュール

open my $FH, '<:utf8', $ARGV[0];     # 入力する文字コードが何なのかを明示する
for my $line(<$FH>){
    chomp $line;
    print encode('cp932', $line) . "\n";    # 出力する文字コードは何なのかを明示する 
}
close $FH;

Windowsコマンドプロンプト文字コードを utf8 にする

コマンドプロンプトchcp 65001 というコマンドを実行することで、コマンドプロンプト文字コードを utf8 に変更できます。

この方法をとる場合、変更すべきはバッチファイルの方になります。

@echo off
setlocal
cd /d %~dp0

rem コマンドプロンプトの文字コードを utf8 に変更
chcp 65001

perl open_text.pl %~f1

pause

f:id:sironekotoro:20210131155825p:plain

こんな感じで

Perl の便利さ + Windows での慣れた GUI 操作 両方のいいとこ取りで、仕事を楽にしていきましょう!

おまけ

7年くらい前、Windows マシンで Perl を勉強していた自分は、この文字コードがどうとかエンコードとか理解できませんでした。

そして Mac を買うという解決策をとったのでした。

Mac はターミナル(Windows でいうところのコマンドプロンプト)の文字コードが utf8 なので文字コードを意識する必要がなかったんですね。

あと、当時はみんな Mac だったなぁという。形から入りました。

・・・とはいえ、ネットから落としてきた何かや、スクレイピングで得た文字列を扱うときには文字コードの問題はついて回るので、結局逃げられなかったという感じです。

追記

バッチファイルから Perl にファイルパスを渡す時なのですが

perl hello.pl %~f1

よりも

perl hello.pl "%~f1"

の方が良いです。

ファイルパス中にスペースがあった場合、スペース以降の文字列を引数として認識してしまいます。

このため、ファイルパスをダブルクォーテーション " " で囲むことで、ひとまとまりの文字列として扱うことができます。

もちろん、この問題でしっかりハマりました。