usp 友の会 lt 資料 20130413
TRANSCRIPT
自己紹介
斉藤 博文 日本 GNU AWK ユーザー会主宰 @hi_saito [email protected] Shell + AWK 最強 !
サイトから画像を一括並列ダウンロード
ひとつひとつの画像をブラウザから右クリックで保存するのは面倒ですよね。
画像を抜き出して保存する専用アプリもあるようですが、「シェル芸」で十分です。
LL だと並列ダウンロードするのに fork とかを使いますが、使い方が良く分からないという人もいるんじゃないでしょうか。
使うもの
bash wget
curl でも可能ですが、今回の場合には wget の方が便利です。
tr egrep (grep) sort sed xargs
手順を記述してみる
1. 画像のあるサイトの HTML を落とす。2. アトリビュートを分割する。3. 画像を抜き出す。4. ダブっていたら無駄なのでダブらいないよう
にする。5. 必要に応じて絶対 URL に変換する。6. 並列に分割して画像を落とす。
$ wget -O - http://www.usptomo.com/ |\ tr "\"" "\n" |\ egrep "\.(JPG|PNG|GIF)" |\ sort -u |\ sed 's|^|http://www.usptomo.com|' |\ xargs -P0 -n1 wget
コードにしてみる
xargs で -PN で N 並列実行ですが、 -P0 で可能な限り並列実行します。
xargs の -nN で N 個単位で分割しますので、 -n1 だと結果的に全て並列処理になります。
ちょっとしたコツ
HTML からリンク先を抜き出すには tr で分割すると便利な場合が多いです。
egrep は括弧でグルーピングができるので拡張子をまとめて記述することができます。 もちろん、 tr と egrep を awk でま
とめて記述することもできます。
並列分割ダウンロード
巨大なファイルをダウンロードしたい。 サーバーが 1 接続あたりの回線速度を制限
しているため十分な速度が出ていない。 並列分割ダウンロードする OSS はあまりな
いよね。
使うもの
bash curl
今回は wget ではなく curl が必要です。 sed awk etc.
手順を記述してみる
1. 対象のファイルサイズを取得する。2. サイズを分割数で割る。3. ナンバリングして並列で落とす。4. 親プロセスは落とし終わるまで待つ。5. 分割したものを結合する。
#! /bin/bashDIV=5URL=$1FILE=$(basename ${URL})PID=$$
CONTENT_LENGTH=$(curl -s --head ${URL} |\ sed 's|\r||' |\ awk '/^Content-Length/ {print $2}')
対象のファイルサイズを取得
curl は --head でヘッダーのみを取得できます。
for i in `seq 1 ${DIV}`; do START_BYTE=$(echo "${CONTENT_LENGTH} \ / ${DIV} * (${i} - 1)" | bc) END_BYTE=$(echo "${CONTENT_LENGTH} \ / ${DIV} * ${i} - 1" | bc)
if [ ${i} -eq ${DIV} ]; then END_BYTE=${CONTENT_LENGTH} fi
サイズを分割数で割る
分割して落とす先頭バイト数と終了バイト数を計算します。
TMP_FILE=$(printf "%d-%02d-%s" \ ${PID} ${i} ${FILE})
curl -s --range ${START_BYTE}-${END_BYTE} \ -o ${TMP_FILE} ${URL} &done
ナンバリングして並列で落とす
curl は --range で落とす範囲を指定することができます。
wait
cat $$-* > ${FILE}
rm -f $$-*
落とし終わるまで待って結合
wait 単独だと全ての子プロセスの終了を待ちます。
使うもの
bash bash の記述を使っています。
cal awk convert (ImageMagick)
$ cal April 2013Su Mo Tu We Th Fr Sa 1 2 3 4 5 6 7 8 9 10 11 12 1314 15 16 17 18 19 2021 22 23 24 25 26 2728 29 30
cal コマンドの基本形
cal コマンドは何も引数がないと今月のカレンダーを表示します。
$ convert -font Ricty-Bold.ttf \ -pointsize 40 \ -fill black \ -draw "text 120,450 \"$(cal)\"" \ iphone.png calendar.png
ImageMagick で画像に変換
ImageMagick は日本語 TTF も扱えます。
文字列だけでなく、コマンドを埋め込めます。
$ cal | awk '$0=substr($0, 1, 2)'
Su
7142128
日曜日だけを抜き出す
この awk の使い方分かりますか ? アクションがないのに表示できていますよね。
アクションレスプログラミング
awk はパターン + アクションですよね。 でも、アクションがない場合は '{print
$0}' が省略されたものと見なれます。 また、 awk では基本的に代入は「真」にな
ります。$0=substr($0, 1, 2)
{ $0 = substr($0, 1, 2); print $0;}
等価 !
$ cal | awk '$0=sprintf("%20s",substr($0, 19, 2))'
Sa 6 13 20 27
土曜日だけを抜き出す
これもアクションレスプログラミングですね。 ここまでくれば、あとは同じです。
$ convert -font Ricty-Bold.ttf -pointsize 40 \ -fill black -draw "text 120,450 \ \"$(cal)\"" \ -fill red -draw "text 120,450 \ \"$(cal|awk '$0=substr($0, 1, 2)')\"" \ -fill blue -draw "text 120,450 \ \"$(cal|awk '$0=sprintf("%20s",substr($0,19,2))')\"" \ iphone.png calendar.png
最終形態
ほらね。「シェル芸」でできるでしょ。
特定の日付だけを出す方法は ?
特定の日付だけを抜き出すことができれば、今日や国民の休日をマーキングすることもできますね。
土日と比べると複雑ですが、やってみてください。$ cal | awk -v day="${DAY}" -v str="@" \
'{ regexp = "(^| )" day "( |$)"; $0 = gensub(regexp, "\\1@\\2", 1, $0);}{gsub(/[^@]/, " ")}{sub(/@/, day)}1'
最終的には ?
最終的には cron に crontab で登録して毎月 1 日に更新し、メールで iPhone に送るようにすると便利です。