2014/03/03

PowerShellで「mysql.exeで外部SQLファイルを引数に使う」方法 の補足

少し前「PowerShellで「mysql.exeで外部SQLファイルを引数に使う」方法」という記事を書き、大反響(アクセス数合計15くらい)をいただいております。
需要のなさがよくわかる数値ですね。ありがとうございます。

さて、その中で紹介した構文
PS >Get-Content .\hogehoge.sql | mysql -u myuser -p
ですが、この外部ファイルにマルチバイト文字を使っている場合、そのままでは文字化けることが判明したので補足エントリです。



.


答えから先に書くと、仮にこの外部ファイルがUTF-8で書かれている場合、以下のように書き直す必要があります。
PS >$OutputEncoding = [text.encoding]::GetEncoding('UTF-8')
PS >Get-Content .\hogehoge.sql -Encoding 'UTF8' | mysql -umyuser -p

ここでのポイントは二つ

読み取る際の文字コード

Get-Content ~ -Encoding 'UTF8'
でファイルから読み取る際の文字コードを指定します。

これをしないと文字化けした状態で読み取られ、文字化けしたまま引き渡されるので、
検索にヒットしなかったり、文字化けした文字列が挿入されたり、途中で構文エラー等で失敗したりします。


引き渡す際の文字コード

$OutputEncoding = [text.encoding]::GetEncoding('UTF-8')
でアウトプット(=mysql.exeに渡す)の文字コードを指定します。

これをしないと文字化けして引き渡されるので、
検索にヒットしなかったり、文字化けした文字列が挿入されたり、途中で構文エラー等で失敗したりします。
当然引き渡す前に指定しておく必要があるので先に書きます。


UTF8? UTF-8?

Get-Contentの-Encodeオプションの引数指定は 'UTF8'
[text.encoding]::GetEncoding()の引数指定は 'UTF-8'
とそれぞれ書式が違いますが、それぞれこの通りに書かないとエラーになります。
うん、しんだらいいよ。


もっと詳しい話

すごい人がこんな記事を書いてくれています。
(参考)クラシック コマンドと PowerShell の間のエンコード設定
http://d.hatena.ne.jp/ladybug/touch/20111203
引用:PowerShell ではコマンド間の入出力はオブジェクトのストリームになりました。これは、PowerShell とクラシックなコンソール コマンドの間ではオブジェクトとバイナリの間のマーシャリングが必要になるということです。また、PowerShell はコンソール コマンドとのデータのやりとりを文字列ベースで行おうと努力します。
概念が理解できてない私には、なんか、すごい、難しいです。
想像では.NET Frameworkの仕様にも関係してるんじゃないかと思ったりするんですが、むつかしいことはよくわかりません。


私なら

パイプで引き渡すメリットとしては元の文字コードから別の文字コードに変換できたり、文字列加工をできることでしょうか。
私なら気持ち悪いのでやりたくないです。

「俺は文字コードと戦いたいんじゃない。mysqlを使いたいだけなんだ。」という方は、前回も紹介した mysql.exe の --execute オプションと sourceコマンドを合わせた以下の書式がよいと思います。
PS >mysql -umyuser -p -e"source .\hogehoge.sql"
これならPowerShellのコンソールが外部ファイルを読みに行くことはなく、世界に平和が訪れます。

.

1 件のコメント:

  1. この記事を読んで解決ししました。ありがとうございました。

    返信削除