Gre's Blog(跡地)

※更新していません。中の人の詳細→ gr3.ie

grepの-oオプションと-Pオプションの組み合わせが便利

上記のようにgrepコマンドを叩いていたら「-oPってオプションなに?」と言われたので。

grep -oPって?

-oオプションとは

--only-matchingの略。マッチした部分のみを抽出するというオプションのこと。

$ echo "123abc456dfg" | grep -o [a-z]
a
b
c
d
f
g

-Pオプションとは

マッチさせる文字列にPerlで使われているものと同じ正規表現(Perl正規表現)をつかえるようにする。PerlのP。

普通の正規表現Perl正規表現の違いって?

主に以下の3つ。

  • 一部のメタ文字が使える [参考]
    • \d、\D、\w、\W、などなど
  • 最長一致、最短一致 [参考]
    • A+ だけじゃなく A+?
  • 先読み、後読み [参考]

これらの特徴はPerl正規表現のみであり、 拡張正規表現オプション(-E)をつけたとしても 使うことはできない。

つまり-oPとすれば

Perl正規表現でマッチした部分のみを抽出できる

$ echo "123abc456dfg" | grep -oP '\d'
1
2
3
4
5
6

どんな時に使える?

grepだけでテキストの「行の抽出」と「切り出し」が同時に行える。

具体例

たとえばこんなexample.xmlという名前のXMLファイルがあったとする。こいつからname要素内のテキスト、それも鍵カッコがついているもののみで、かつ(「」)で囲まれている中身だけを取り出したい。



  
    「Cure Lovely」
  
  
    「Cure Princess」
  
  
    「Cure Honey」
  
  
    「Cure Fortune」
  
  
    Cure Gorilla
  

"Cure Gorilla"以外の下のような出力を得たい。さあ、どうする?

Cure Lovely
Cure Princess
Cure Honey
Cure Fortune
  • 安直に思いつく方法。
$ cat example.xml |
  grep '「' |
  sed 's/.*「//' |
  sed 's/」.*//g'
  • XMLだからと言ってxpathを使うと逆に手間がかかる。
$ cat example.xml |
  xmllint --xpath '//name[contains(./text(),"「")]/text()' - |
  nkf --numchar-input |
  sed -r 's/(「|」)/\n/g'
$ cat example.xml |
  awk -F'[「」]' 'NF>2{print $2}'
$ cat example.xml |
  sed -nr '/「/{s/.*「//g;s/」.*//gp}'

実はgrepだけでいける

$ cat example.xml |
  grep -oP '(?<=「).+(?=」)'

しくみ

Perl正規表現の「先読み・後読み」のパターンで文字列をマッチさせたとしても、 (?~)の中の文字列に関しては、grepの出力時にはマッチした文字列としてみなされない。試しに--colorオプションをつけても、「先読み・後読み」でマッチした部分は色は変化しない。

  • grep -oP '(?<=).+(?=)'
    • 先読みのマッチ部分
    • grepでマッチしたとみなされる部分
    • 後読みのマッチ部分

おそらくUNIXコマンド類の初学段階だと、awksedは文字列の「切り出し」、grepは「行の抽出」に使えるという認識になると思う。そして、学んでいくにつれてawksedもまた、「切り出し」のみならず「行の抽出」も同時にできるということがわかってくる。

しかし行の抽出にしか使えないと思われていたgrepも、実は-oPをつければ、文字列の「切り出し」にも使えますよというお話でした。

WMPから読み込んだmp3ファイルのID3タグの文字化けが治らない理由

自宅サーバに音楽ファイルを入れて家の中からPCやiPadでアクセスして音楽を聴いているが、どうも昔Windows Media Playerでインポートしたmp3ファイルのメタ情報の文字化けが残ったままだった。

色々ググってみたところ文字化けをするのはmp3ファイルのメタ情報(ID3タグ)がShift-JIS(以下、SJIS)で保存されているのが原因らしい。併せてEasyTAGなるソフトウェアで治せるとの情報があり、試してみたが、結局直すことができなかった。
なぜ治せないのだろうか?と思い、mp3ファイルのメタ情報を16進数で出力してみたら、ちょっと気になった点があった。音楽のメタ情報についての知識は疎いので、これから話すことの理由についてよくご存じの方が居たら詳しく教えていただきたい。


私の音楽フォルダにある「葉加瀬太郎 - 情熱大陸.mp3」というファイルのタグ情報をmid3v2コマンドで表示するとこのようになる。ターミナルソフト上ではUTF-8以外のマルチバイト文字は文字化けするようになっているため、やはりID3タグ情報は文字化けしている。

f:id:greymd:20140924233548p:plain

例えばTALBの部分はおそらくアルバム名であろう。ここは本来は「情熱大陸」となっているはずである。

ここで下の画像のようにアルバム名の文字化け部分だけをシェルで切り出す。
確かになんとなく4文字ということはわかる。

f:id:greymd:20140924233716p:plain


od -xにより16進数表示をする。


f:id:greymd:20140924233831p:plain

8f c2 ae c3 94 c2 c2 4d c3 91 c2 a5 c2 97 0a a4

するとなぜか16バイト分の文字列が出現する。はて、SJISは2バイト文字ではなかっただろうか?なぜ8バイトではないのだろうか。

そこで試しに純粋なSJISの「情熱大陸」という文字列は、16進数で表すとどのようになるのかを、下記のコマンドで調べてみる。

f:id:greymd:20140924233900p:plain

ee 8f 4d 94 e5 91 a4 97 00 0a

すると、見事に8バイトである。つまりID3タグに含まれていた情報はSJISではなかったのか……?
ここで、ID3タグの文字列と、正規のSJISの文字列の16進数版を比較してみよう。

  • ID3タグ内の「情熱大陸」という文字列の16進数表記

8f c2 ae c3 94 c2 c2 4d c3 91 c2 a5 c2 97 0a a4

ee 8f 4d 94 e5 91 a4 97 00 0a


すると、どうも法則性があるような気がする。
ID3タグ情報は、本来ならば2バイト文字であるSJISの文字を、1バイトずつに分割し、c2、あるいはc3という1バイトを付与しているような気がする。しかし具体的な法則性を考察するのは面倒なのでやめる。


つまり、愚直に純粋なSJISからUnicodeへ変換しようとしていたEasyTAGでは、この文字化けは治せなかったということなのかもしれない。
このようなファイルに関してはMp3tagやID3Uniなどのソフトを使って文字化けを直すことができた(参考)が、果たしてこれらのソフトウェアはどのようにして文字エンコードを変換しているのだろうか?

試しにID3UniのREADMEを読んでみたが、やはりSJISからUnicodeへ変換するソフトであるという旨が書いてあった。正確にはコイツが変換している文字列はSJISとは似て非なるものなのだが……。

これは仮説だが、もしかしたら、.NET Frameworkなどを使用すると、フレームワークがメタ情報の扱い方を隠蔽化してしまっているのかもしれない。ゆえに、開発者はファイルからメタ情報を取り出したり、更新したりすることはできるが、実際に書き込まれているバイト列までは意識しなくて良い開発環境が整っているのかもしれない。

だがそもそもの話、なぜこのような似非SJISバイト列になっているのだろうか?SJISには2バイト目が5C等になりうることによる問題がある。それを防ぐための方策だろうか?
いずれにしても、Windows Media Playerで音楽を取り込むのは今後控えておこう……。

Cygwinのインストール方法+α

この記事では基本的なCygwin*1のインストール手順に加えて、とりあえず私が最初にやっておいた方が良いと思う下記の2点について説明する。

  • apt-cygを使えるようにしておく
  • カレントディレクトリでCygwinを開けるようにしておく

この記事の内容は、既に存在するCygwinのインストール手順について説明したサイトとほとんど同じである。
しかし、既存サイトは、大学の講義での使用を目的とした解説や、特定のソフトウェアの利用のみを目的としたものが散見され、必ずしも万人が使うとは限らないパッケージの導入について述べていることが多い。

そこで本記事は、私の知人たちを初めとした「特定の目的はないが、コマンドを使って日々のファイル・文字列操作を楽にしたい人」向けに説明するものである。

*1:対象とするのは64bit版のCygwinである。32bit版で同様のインストール手順を踏む場合は"cygwin64"という文字列を"cygwin"に置き換えるとできるかもしれない。

続きを読む

HandBrakeCLIで品質を指定して動画を変換

DVDのISOイメージから、mp4へ動画を変換するのに、HandBrakeというソフトを使った。このソフトの良いところはHandBrakeCLIという、コンソール上で変換をするための実行ファイルも付属していることだ。このおかげで、UNIX系のコマンドを利用して、複雑に入り組んだディレクトリの中から、特定の条件に合致する動画ファイルを変換することができる。

HandBrakeCLI -i input.iso -o output.mp4

ちなみに動画の品質を指定して変換する場合は、--qualityオプションに続いて、品質を表す文字列を併記する必要がある。こんな感じに。

HandBrakeCLI --quality "RF:15" -i input.iso -o output.mp4

文字列は"RF:○○"という数字を含んだフォーマットに従う。15~35くらいのレンジで変化できて、数字が小さいほど高画質。品質の詳細は下記サイトにあった。 参考