はじめに
前回は、はてなブログAPIのレスポンスを1行にまとめるところまでを作った。
今回は、そこから指定したタグの値を取り出すスクリプトを作成しよう。
つくるもの
使い方は、前回の出力をパイプで受け取る感じ。
(h-entry-getitems
が今回のスクリプト)
> cat SAMPLE | h-entry-pickup detail | h-entry-cleantags | h-entry-perline | h-getitems
動作例
以下が加工前のデータ。1つの記事(entryタグ)が1行になっている。 (記事のコンテンツは無し)
> cat SAMPLE <entry><edit>https://blog.hatena.ne.jp/{はてなID}/{ブログID}/atom/edit/2500000000</edit><alternate>http://{ブログID}/entry/2013/09/02/112823</alternate><author>{はてなID}</author><title>記事タイトル1</title><updated>2013-09-02T11:28:23+09:00</updated><published>2013-09-02T11:28:23+09:00</published><app:edited>2013-09-02T11:28:23+09:00</app:edited><summary> 記事本文 リスト1 リスト2 内容 </summary><category>カテゴリ1</category><category>カテゴリ2</category><app:draft>no</app:draft></entry> <entry><edit>https://blog.hatena.ne.jp/{はてなID}/{ブログID}/atom/edit/2500000000</edit><alternate>http://{ブログID}/entry/2013/09/02/112823</alternate><author>{はてなID}</author><title>記事タイトル2</title><updated>2013-09-02T11:28:23+09:00</updated><published>2013-09-02T11:28:23+09:00</published><app:edited>2013-09-02T11:28:23+09:00</app:edited><summary> 記事本文 リスト3 リスト4 内容 </summary><category>カテゴリ3</category><category>カテゴリ4</category><app:draft>no</app:draft></entry>
与えられた引数の項目(XMLタグ)の値を、与えられた順番で出力する。
区切り文字は>
固定にしている。
> cat SAMPLE | h-entry-getitems title 記事タイトル1 記事タイトル2 > cat SAMPLE | h-entry-getitems published title category 2013-09-02T11:28:23+09:00>記事タイトル1>カテゴリ1 2013-09-02T11:28:23+09:00>記事タイトル2>カテゴリ3
指定した項目が存在しなかった場合、その項目は空文字で出力する。
> cat SAMPLE | h-entry-getitems title DUMMY category 記事タイトル1>>カテゴリ1 記事タイトル2>>カテゴリ3
引数がない場合は、全項目を出力する。
> cat SAMPLE | h-entry-getitems https://blog.hatena.ne.jp/{はてなID}/{ブログID}/atom/edit/2500000000>http://{ブログID}/entry/2013/09/02/112823>{はてなID}>記事タイトル1>2013-09-02T11:28:23+09:00>2013-09-02T11:28:23+09:00>2013-09-02T11:28:23+09:00> 記事本文 リスト1 リスト2 内容 >カテゴリ1>カテゴリ2>no https://blog.hatena.ne.jp/{はてなID}/{ブログID}/atom/edit/2500000000>http://{ブログID}/entry/2013/09/02/112823>{はてなID}>記事タイトル2>2013-09-02T11:28:23+09:00>2013-09-02T11:28:23+09:00>2013-09-02T11:28:23+09:00> 記事本文 リスト3 リスト4 内容 >カテゴリ3>カテゴリ4>no
コード
今回のコードはこちら。
何か変なところがあればご指摘下さいまし。
ざっくり説明すると下記となる。
2行目
出力の際の区切り文字4行目以降
引数なしの場合。全てのXMLタグを除去する14行目以降
引数ありの場合。引数で指定した項目を指定した順番で取り出して、1行ずつ出力する
ワンライナー以外のawk
のスクリプトを初めて書いた気がする。
他の方法が思い浮かばなかったときの最終兵器感がありますな。
awk
を使った箇所は、ちょっと処理の補足をしておこう。
引数ありの場合の補足
pick_tags= for tag in "$@"; do # ,<tag1>,<tag2>.... pick_tags="$pick_tags,<$tag>" done # ,<tag1>,<tag2> # <tag1>,<tag2> pick_tags=${pick_tags#,} awk -v target="$pick_tags" -v target_num=$# \ 'BEGIN { \ split(target, tags, ","); for (i=1; i<=target_num; i++) { len[i]=length(tags[i]) tags[i]=tags[i] "[^<]*"; } }{ fields="" for (i=1; i<=target_num; i++) { where=match($0, tags[i]); if (where == 0) { fields=fields "'$PLANE_TEXT_SEP'" }else { fields=fields "'$PLANE_TEXT_SEP'" substr($0, RSTART+len[i], RLENGTH-len[i]); } } sub(/^'"$PLANE_TEXT_SEP"'/, "", fields) print fields }'
最初に、可変個の引数をawk
に渡したいため、pick_tags
という1つの変数に引数をまとめている。
その際、各引数にタグの<
と>
も追加しておく。
次に、awk
起動する際に、引数と引数の個数を渡している。
awk
ではオプションの-v variable=value
で変数を起動時に定義できるっぽい。
次のBEGIN
ブロックは、awk
で入力の1行目を処理する前に実行されるブロック。
ここでは、引数を配列に変換して各行で探す検索パターンを構築している。
ここで変換した配列の数だけ、各入力行でループを回しながら検索する力技。
構築している検索パターンは、<タグ名>[^<]*
。
最終的に欲しいのは値だけなので、検索ヒット位置から値だけを取り出す際のオフセットとなる<タグ名>
の文字数もlen
に保存しておく。
BEGIN
の次のブロックが、各入力行に対して実行されるブロック。
BEGIN
で作った検索パターンにマッチしたものを、fields
に入れている。
検索にはmatch
関数を使い、戻り値が0
ならマッチしなかったことを示すため、区切り文字だけセットしている。
マッチした場合は、タグの値だけ取り出す為、substr
関数を使っている。
match
関数は、RSTART
にマッチ開始位置、RLENGTH
はマッチした文字数をセットしてくれるっぽい。
sub
関数を使っているのは、先頭の余計な区切り文字を除去するため。
最後にprint
関数で取得した1行分の項目を出力している。
うーん、実にシェルスクリプトっぽくない感じ。
ちなみに同じような処理を最初シェルスクリプトのループで書いてみたのだけれども、うるとらはいぱー遅かった。
awk
すっごい。
最後に
今回のスクリプトで、はてなブログAPIのレスポンスから好きな項目を取り出せるようになった。
これで、記事のタイトルやカテゴリ、URLなど任意の項目の一覧表を簡単に作れるはずだ。
実際は、作ってきたスクリプト達の実行をまとめたラッパースクリプトを用意するといいかと思う。
さて、ここまでは記事のコンテンツ以外の項目を取り出すものを作ってきた。
次回は、取得した記事のコンテンツと一緒に、必要な情報をmdファイルに保存するスクリプトでも作ってみよう。
確認環境
PC | Thinkpad X1 Carbon 2nd Gen |
OS | 12.0-RELEASE-p7 |
参考
以上。