ワンライナー

あるシステムの入力項目から入力されたテキストデータから、カタカナを強制的にアルファベット(ローマ字)へ変換したいという要件が出てきました。さすがにワンライナーでやるにはキツいので、sedの置換ファイルを作ってやるのが楽ですね。

s/キャ/kya/g
s/キュ/kyu/g
s/キョ/kyo/g
s/ギャ/gya/g
s/ギュ/gyu/g
s/ギョ/gyo/g
s/シャ/sha/g
s/シュ/shu/g
s/ショ/sho/g
s/ジャ/ja/g
s/ジュ/ju/g
s/ジョ/jo/g
s/チャ/cha/g
s/チュ/chu/g
s/チョ/cho/g
s/ヂャ/ja/g
s/ヂュ/ju/g
s/ヂョ/jo/g
s/ニャ/nya/g
s/ニュ/nyu/g
s/ニョ/nyo/g
s/ヒャ/hya/g
s/ヒュ/hyu/g
s/ヒョ/hyo/g
s/ビャ/bya/g
s/ビュ/byu/g
s/ビョ/byo/g
s/ピャ/pya/g
s/ピュ/pyu/g
s/ピョ/pyo/g
s/ミャ/mya/g
s/ミュ/myu/g
s/ミョ/myo/g
s/リャ/rya/g
s/リュ/ryu/g
s/リョ/ryo/g
s/ファ/fa/g
s/フィ/fi/g
s/フェ/fe/g
s/フォ/fo/g
s/ティ/thi/g
s/ディ/dhi/g
s/ヴァ/va/g
s/ヴィ/vi/g
s/ヴ/vu/g
s/ヴェ/ve/g
s/ヴォ/vo/g
s/ア/a/g
s/イ/i/g
s/ウ/u/g
s/エ/e/g
s/オ/o/g
s/カ/ka/g
s/ガ/ga/g
s/キ/ki/g
s/ギ/gi/g
s/ク/ku/g
s/グ/gu/g
s/ケ/ke/g
s/ゲ/ge/g
s/コ/ko/g
s/ゴ/go/g
s/サ/sa/g
s/ザ/za/g
s/シ/shi/g
s/ジ/ji/g
s/ス/su/g
s/ズ/zu/g
s/セ/se/g
s/ゼ/ze/g
s/ソ/so/g
s/ゾ/zo/g
s/タ/ta/g
s/ダ/da/g
s/チ/chi/g
s/ヂ/ji/g
s/ツ/tsu/g
s/ヅ/zu/g
s/テ/te/g
s/デ/de/g
s/ト/to/g
s/ド/do/g
s/ナ/na/g
s/ニ/ni/g
s/ヌ/nu/g
s/ネ/ne/g
s/ノ/no/g
s/ハ/ha/g
s/バ/ba/g
s/パ/pa/g
s/ヒ/hi/g
s/ビ/bi/g
s/ピ/pi/g
s/フ/fu/g
s/ブ/bu/g
s/プ/pu/g
s/ヘ/he/g
s/ベ/be/g
s/ペ/pe/g
s/ホ/ho/g
s/ボ/bo/g
s/ポ/po/g
s/マ/ma/g
s/ミ/mi/g
s/ム/mu/g
s/メ/me/g
s/モ/mo/g
s/ヤ/ya/g
s/ユ/yu/g
s/ヨ/yo/g
s/ラ/ra/g
s/リ/ri/g
s/ル/ru/g
s/レ/re/g
s/ロ/ro/g
s/ワ/wa/g
s/ヲ/wo/g
s/ン/n/g
s/ー/-/g

例えば大岡山(オオオカヤマ)をカタカナからローマ字に変換するにはこうします。

$ echo "オオオカヤマ" | sed -f katakana2alpha.sed
oookayama

先頭文字のみを大文字にするには、awkのワンライナーを使うと便利です。今回のワンライナーは py4s-tnk さんの一行パk・・・参考にさせていただきました。

$ echo "オオオカヤマ" | sed -f katakana2alpha.sed | awk '{print toupper(substr($1,1,1))substr($1,2)}'
Oookayama

上に貼り付けたコードをご覧いただけるとおわかりいただけるかと思いますが、2文字で発音する文字をファイルの最初に持ってきています。こうすることで、「貴社の記者は汽車で帰社した(キシャノキシャハキシャデキシャシタ)」をうまく変換することができます。

$ echo "キシャノキシャハキシャデキシャシタ" | sed -f katakana2alpha.sed 
kishanokishahakishadekishashita

もしこの工夫がなければ・・・

$ echo "キシャノキシャハキシャデキシャシタ" | sed -f katakana2alpha.sed 
kishiャnokishiャhakishiャdekishiャshita

このように、1文字目でマッチさせてしまうため、拗音があると無視されてしまうのです。拗音だけの変換テーブルを作ってやればいいじゃんという声もあるかも知れませんが、そもそも拗音だけ発音するという機会はないので作っていません。

どうしてもファイルを作りたくないという方はワンライナーでどうぞ。

$ echo "キシャノキシャハキシャデキシャシタ" | sed -e "s/キャ/kya/g;s/キュ/kyu/g;s/キョ/kyo/g;s/ギャ/gya/g;s/ギュ/gyu/g;s/ギョ/gyo/g;s/シャ/sha/g;s/シュ/shu/g;s/ショ/sho/g;s/ジャ/ja/g;s/ジュ/ju/g;s/ジョ/jo/g;s/チャ/cha/g;s/チュ/chu/g;s/チョ/cho/g;s/ヂャ/ja/g;s/ヂュ/ju/g;s/ヂョ/jo/g;s/ニャ/nya/g;s/ニュ/nyu/g;s/ニョ/nyo/g;s/ヒャ/hya/g;s/ヒュ/hyu/g;s/ヒョ/hyo/g;s/ビャ/bya/g;s/ビュ/byu/g;s/ビョ/byo/g;s/ピャ/pya/g;s/ピュ/pyu/g;s/ピョ/pyo/g;s/ミャ/mya/g;s/ミュ/myu/g;s/ミョ/myo/g;s/リャ/rya/g;s/リュ/ryu/g;s/リョ/ryo/g;s/ファ/fa/g;s/フィ/fi/g;s/フェ/fe/g;s/フォ/fo/g;s/ティ/thi/g;s/ディ/dhi/g;s/ヴァ/va/g;s/ヴィ/vi/g;s/ヴ/vu/g;s/ヴェ/ve/g;s/ヴォ/vo/g;s/ア/a/g;s/イ/i/g;s/ウ/u/g;s/エ/e/g;s/オ/o/g;s/カ/ka/g;s/ガ/ga/g;s/キ/ki/g;s/ギ/gi/g;s/ク/ku/g;s/グ/gu/g;s/ケ/ke/g;s/ゲ/ge/g;s/コ/ko/g;s/ゴ/go/g;s/サ/sa/g;s/ザ/za/g;s/シ/shi/g;s/ジ/ji/g;s/ス/su/g;s/ズ/zu/g;s/セ/se/g;s/ゼ/ze/g;s/ソ/so/g;s/ゾ/zo/g;s/タ/ta/g;s/ダ/da/g;s/チ/chi/g;s/ヂ/ji/g;s/ツ/tsu/g;s/ヅ/zu/g;s/テ/te/g;s/デ/de/g;s/ト/to/g;s/ド/do/g;s/ナ/na/g;s/ニ/ni/g;s/ヌ/nu/g;s/ネ/ne/g;s/ノ/no/g;s/ハ/ha/g;s/バ/ba/g;s/パ/pa/g;s/ヒ/hi/g;s/ビ/bi/g;s/ピ/pi/g;s/フ/fu/g;s/ブ/bu/g;s/プ/pu/g;s/ヘ/he/g;s/ベ/be/g;s/ペ/pe/g;s/ホ/ho/g;s/ボ/bo/g;s/ポ/po/g;s/マ/ma/g;s/ミ/mi/g;s/ ム/mu/g;s/メ/me/g;s/モ/mo/g;s/ヤ/ya/g;s/ユ/yu/g;s/ヨ/yo/g;s/ラ/ra/g;s/リ/ri/g;s/ル/ru/g;s/レ/re/g;s/ロ/ro/g;s/ワ/wa/g;s/ヲ/wo/g;s/ン/n/g;s/ー/-/g"

以上、sed awkの小ネタでございました。

[amazonjs asin="477417369X" locale="JP" title="AWK実践入門 (Software Design plus)"]

ニチアサですね、おはようございます。 @nullpopopo でございます。雑誌に掲載する写真を選んでいるのですが、いただいた写真はiPhoneで撮影したものとデジカメで撮影したものが混在していました。前者はタイムスタンプがそのままファイル名になったYYYY-MM-DD_HH.MM.SS.jpg、後者はDSCNNNNN.JPGという連番ファイル名です(蛇足ですがAndroid携帯のファイル名ですとDSC_NNNN.JPGなので、今回取り上げるワンライナーで応用が効くかと)。

これをパソコン(Fedora20)に取り込んで時系列で順番に見たいのですが、コマンドラインですと「ls --full-time」で時系列に並べ替えることができます。しかしnautilusでサムネイル表示するのに、1回1回更新日時順にソートするのも面倒です。じゃあデジカメ画像のほうをリネームしてしまえ!ということで以下のワンライナーを実行。

ls --full-time DSC* | awk '{print "mv",$NF,$6"_"$7"_"$NF}' | sed -e 's/.000000000//g;s/:/./g;s/JPG$/jpg/g' | sh

lsコマンドに--full-timeオプションをつけたときの表示はこんな感じです。

$ ls --full-time DSC* | head -n 1
-rw-r--r-- 1 hamada hamada 1748093 2014-11-04 09:13:48.000000000 +0900 DSC04071.JPG

この出力結果をawkに食わせるのですが、もうここでmvコマンドを表示させてしまいます。実行結果は以下の通り。

$ ls --full-time DSC* | head -n 1 | awk '{print "mv",$NF,$6"_"$7"_"$NF}'
mv DSC04071.JPG 2014-11-04_09:13:48.000000000_DSC04071.JPG

しかしこれだけですと、単に実行したいコマンドが標準出力に表示されるだけでなく、日付のフォーマットもiPhoneのファイル名と異なります。また、拡張子が大文字のままです。なので、リネーム後のファイル名をsedで整形してしまいましょう。なお、元のファイル名(DSCNNNNN)は、iPhoneのファイル名と衝突しないよう、また、元々がデジカメのファイル名だったことがlsだけでわかるように残すこととします。

$ ls --full-time DSC* | head -n 1 | awk '{print "mv",$NF,$6"_"$7"_"$NF}' | sed -e 's/.000000000//g;s/:/./g;s/JPG$/jpg/g'
mv DSC04071.JPG 2014-11-04_09.13.48_DSC04071.jpg

いい感じですね。あとはパイプでshコマンドに渡してあげればリネームできてしまいます。ワンライナーやシェルスクリプトの実行結果が予想できないうちは、このように標準出力に表示させておいて、最後に一気にshに渡してしまうクセをつけると、何度も確認しながらコマンドを組み立てることができます。また、複数ファイルのリネームなどをforで回すより実行結果が速くなりますのでオススメですよ。ね、簡単でしょう?

[amazonjs asin="4904807146" locale="JP" tmpl="Small" title="USP MAGAZINE vol.20"]

みなさんこんばんは。いっぱしのシェル芸人たるものawk力を高めなきゃ(使命感)!と尻に火がついた @nullpopopo でございます。今までは文字列の置換にsedを多用していたのですが、awkでフィールド切り出した後にsedで置換するのもカッコ悪い!パイプの本数は少なければ少ないほどよい!と思い立ったわけでして。

はい、正座して斉藤 博文さんの連載を読みました。ちょっととある事情から某所のディスク使用率を継続的に監視したくて、かつテキストでも残したかったので、こんな感じでログ出力するようにしました。

2014/11/22 00:00:00 / 5
2014/11/22 00:00:00 /dev/shm 0
2014/11/22 00:00:00 /boot 12

<日付> <時刻> <パーティション> <使用率> ってフォーマットですね。ちなみに元のdfはこんな感じで出力されます。

$ df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/mapper/VolGroup-lv_root
                       18G  784M   16G   5% /
tmpfs                 499M     0  499M   0% /dev/shm
/dev/vda1             477M   52M  400M  12% /boot

上記dfの結果から見出しの行を削除して、パーティションの列(最終フィールド)と使用率の列(5フィールド目)を抜き出し、単位の「%」を削除してdateコマンドの出力結果を先頭に加えています。これを実現するシェル芸ワンライナーはこちら。

df -P | egrep -v '^(Filesystem|ファイル)' | awk -v date="$(date "+%Y/%m/%d %H:%M:%S")" '{gsub(/%/, ""); print date,$NF,$5}'

dfコマンドのオプションですが、LVMな領域やNASの領域をマウントしている場合に折り返し表示をしないようにしています。ディスク使用率のパーセンテージさえ表示されればよいので他のオプションはつけていません。

次にdfの結果から見出しの行を削除しています。私はどんなサーバーを構築するときも英語環境にする(日本語をインストールしない)のがほとんどなのですが、手元のマシンが日本語環境のFedoraなので、LANGの設定を引き摺ったときでも見出し行が削除されるように、行頭が「Filesystem」と「ファイル」で始まる行を除いたものが出力されるようにしています。

最後にawkで変数の設定、置換、フィールドの切り出しをやっています。最初に「-v」オプションをつけることで、変数「date」にdateコマンドの出力結果をセットします。次に組み込み関数gsubで%を空文字に削除しています。そして最後にいつものprint文でawk変数「date」と最終フィールド($NF)と5フィールド目($5)を出力しています。

こうしてパイプを2本しか繋がずにdfの出力結果を加工することができました。ね、簡単でしょう?

斉藤さんの「シェル芸」に効く AWK処方箋はUSP Magazineで読めますよ!あ、私も恥ずかしながら隔月(偶数月)号で連載させていただいております(コッソリ)。

[amazonjs asin="4904807138" locale="JP" title="USP MAGAZINE vol.19"]

でわ〜(^o^)ノ♪

夜な夜な自家発電に勤しんでいる中高生から中高年の皆様こんばんは。前回、xvideosの動画ダウンロードシェル芸をご紹介いたしましたが、やはりここは海外動画サイトの双璧をなすxhamsterもシェル芸でダウンロードしたいですよね?

xhamsterの動画ページですが、ソースを見てみるとflvとmp4の両方がダウンロードできるようです。こちらのサイトによると「クライアント側のフラッシュが無効時に表示されるmp4ファイルの直リンが稀に書いてあります」とのことですが、いくつかの動画を見てみたところ、稀にどころか100%の確率で両方ダウンロードできました。また、ダウンロードURLはmp4のほうがシンプルでしたので、先にmp4をダウンロードするシェル芸をご紹介しましょう。

[ (っ´∀`)っ@友の会 ~]$ URI=http://jp.xhamster.com/movies/123456/ERO_DOUGA.html ; wget -O $(basename $(dirname ${URI}))_$(basename ${URI} | sed -e 's/html/mp4/') "$(curl -s ${URI} | grep mp4 | grep href | sed -e 's/<a href="//;s/"//' | awk '{print $1}')"

サンプルのURLはダミーです。 http://jp.xhamster.com/movies/123456/ERO_DOUGA.html の最後のディレクトリ「123456」は恐らくユニークな番号が振られているはずです。ただし、htmlファイルの名前は恐らくアップロード者のセンスで命名されていることが推測されるため、ダウンロードしたファイルの重複を防ぐため、「123456_ERO_DOUGA.mp4」としてダウンロードするようにしています。

さて、次にflvのダウンロードですが、こちらはちょっと厄介でした。と言ってもURLエンコードの種類が増えて、かつ連続したURLエンコードの表記があったのと、CDNのURLが「[0-9].xhcdn.com&file=〜〜〜」となっているところを「[0-9].xhcdn.com/key=〜〜〜」にしたくらいでしたが。厄介とか言いながら、じっくりURLを観察してみると意外とすんなりいけました。それではこちらもワンライナーを見てみましょう。例によってURLはダミーです。

[ (っ´∀`)っ@友の会 ~]$ URI=http://jp.xhamster.com/movies/123456/ERO_DOUGA.html ; wget -O $(basename $(dirname ${URI}))_$(basename ${URI} | sed -e 's/html/flv/') $(curl -s ${URI} | grep flv | sed -e 's/%3A/:/g;s/%253A/:/g;s/%252F///g;s/%2B/+/g;s/%2F///g;s/%3F/?/g;s/%2C/,/g;s/%3D/=/g;s/%26/&amp;/g;s/&amp;amp;/ /g;s/srv=/ /;s/xhcdn.com&file=/xhcdn.com/key=/g;s/&image/ /' | awk '{print $4}')

これでダウンロードできました。

なお、動画をダウンロードする際は、いわゆる違法ダウンロードとならないよう、著作権法を守って楽しんでくださいね♡ また、本エントリーに書かれた方法は 2014/10/22 現在動作確認をとっていますが、xhamster側がシェル芸対策を施せば使えなくなる技でもあることをお含みおきくださいΞ(´ ゚_。`)