シェルスクリプトマガジン「Amazonの商品ページURLをきれいにする」をやってみた


毎号とても楽しみにしているシェルスクリプトマガジンのサイトに、
Amazonの商品ページURLをきれいにするという記事があります。

実際に問題に取り組む思考過程が書かれており、大変参考になります。

sedの正規表現を使えばワンライナーでできそうでしたので、
いい勉強になると思いやってみました。

echo "https://www.amazon.co.jp/%E3%82%B7%E3%82%A7%E3%83%AB%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%83%9E%E3%82%AC%E3%82%B8%E3%83%B3-vol-59-%E7%95%B6%E4%BB%B2%E5%AF%9B%E5%93%B2/dp/4904807561/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&keywords=%E3%82%B7%E3%82%A7%E3%83%AB%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%83%9E%E3%82%AC%E3%82%B8%E3%83%B3&qid=1553740346&s=gateway&sr=8-1" |
sed "s/\%.*dp\(.*\)\/.*/dp\1/g"

結果

一応できたのですが、sedの正規表現は一見してわかりづらいため、
自分への備忘録として何をしているのか以下にメモします。

やっていることはamazon.co.jp/URL/dp/文字(数字)/URLのURLを消しています。
\%.*dpでdpの前にある%から始まる文字(%E3%82%B7...E5%93%B2/)をすべて対象とします。
dp\(.*\)\/.*でdp以下の文字(数字)を記憶しつつ、それ以降のすべての文字を対象としています。
そして次のdp\1で、dpの前にある文字をすべて消して、dpの後ろの文字を\1で取り出します。それ以降のすべての文字を消します。

追記1

上のやり方だと%で開始しないURL(商品名が英語など)は対応していないので、より汎用性のある書き方にしました。

echo "https://www.amazon.co.jp/Shell-Programming-Unix-Linux-Developers-ebook/dp/B01L480ILM/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&keywords=POSIX+shell&qid=1574942448&s=english-books&sr=1-3" |
sed "s#amazon.co.jp/.*dp\(.*\)/.*#amazon.co.jp/dp\1#g"

追記2

多少長くなりますが, より可読性が高い書き方です.

echo "https://www.amazon.co.jp/Shell-Programming-Unix-Linux-Developers-ebook/dp/B01L480ILM/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&keywords=POSIX+shell&qid=1574942448&s=english-books&sr=1-3" |
  sed -e "s|\(https*:\)//|\1__|" -e "s|dp/|_dp_|" | # 1行下で区切りを改行にしたときに必要な情報が複数行になるのを避けるため, _でエスケープします 
  tr "/" "\n" | # 扱いやすいように区切りを改行にします
  grep -e "amazon.co.jp" -e "_dp_" | # 必要な情報を抽出します
  awk '$1~/^http/ {printf $1; next}1' | # 1行にまとめます
  tr "_" "/" # エスケープをもとに戻します