シェルスクリプトとPandocでMarkdownをまとめてHTMLに変換してindexファイルも作る
シェルスクリプトとPandocを使って、MarkdownをまとめてHTMLに変換します。
それだけでは芸がありませんので、「シェルスクリプトだけ(sed
,awk
は使う)」「indexファイルも作る」のところでちょっとだけ工夫をしています。
環境
作成例
今回を含めたこのブログ自体の記事を使って作成しました。
コード例と解説
#!/bin/sh # エラー終了の関数 errexit() { printf "\033[31m[ERROR]\033[0m" ; echo " $1" echo "使い方: $0 入力dir 出力dir" exit 1 } generator=`basename $0` echo "\"$generator\" - MarkdownをまとめてHTMLに変換してindexファイルも作る" echo "" # Pandocの有無をチェック test "`which pandoc 2>/dev/null`" || errexit "Pandocがありません" # 引数チェック test "$1" = "" && errexit "入力dirが指定されていません" test "$2" = "" && errexit "出力dirが指定されていません" srcdir=$1 outdir=$2 # dirの有無をチェック test -d "$srcdir" || errexit "入力dirが存在しません" test -d "$outdir" || errexit "出力dirが存在しません" indexfile=$outdir/index.html stylefilename=style.css echo "HTMLファイルの生成を開始." # index.htmlの前半 cat << EOT > $indexfile <!DOCTYPE html> <html><head><meta charset="utf-8" /> <meta generator="$generator" /><title>Documents</title> <link rel="stylesheet" href="$stylefilename"> </head><body><h1>Documents</h1> <p>"$generator"によって`date "+%Y-%m-%d %H:%M:%S"`に生成されました。</p> <ul> EOT # ループ開始 for f in `ls -t $srcdir/*.md` # mdファイルを新しい順に取得 do name=`basename $f` htmlname=`echo $name | sed s/.md$/.html/` /bin/echo -n " 変換: $name -> $htmlname ..." title=`head -n 1 $f | sed 's/#//' | sed 's/^<space>+//'` # タイトルは先頭行を使用 test "$title" = "" && title=$name # タイトルが無い場合はmdファイル名を設定 mtime=`date -r $f "+%Y-%m-%d %H:%M:%S"` # mdファイルの最終更新日時 tempfile=`mktemp temp-XXXXXX` ( echo "% $title" ; cat $f | awk "2<=NR" ) > $tempfile # 先頭行を差し替え pandoc -s -f markdown -t html5 -c $stylefilename -o $outdir/$htmlname $tempfile rm $tempfile echo ".. 完了" echo "<li><a href="./$htmlname">$title</a><br />(最終更新日時:${mtime})</li>" >> $indexfile done # index.htmlの後半 cat << EOT >> $indexfile </ul></body></html> EOT echo "完了しました."
前半のほとんどが準備処理です。
後半のfor
ループの箇所に注目してください。
タイトルを取り出す
先頭行は、# title
の形式を想定していますが、このままPandocで変換するとページのタイトルを付けてくれないので、その対処のために、まずはタイトルを取り出しておきます。
head
で先頭行を取得して、#
とスペースを取り除きます。
先頭行が空の場合は、Markdownファイル名を設定します。
ファイルの最終更新日時
いつの時点のMarkdownファイルなのかを分かるようにするために、indexファイルにファイルの最終更新日時を書いておきます。
環境によっては使えませんが、date -r <file>
でファイルの最終更新日時(mtime
)を取得することができます。
(実はこれ、今回初めて知りました…)
先頭行を差し替え
Pandocの拡張書式でタイトルを処理できるように、先頭行を改竄差し替えます。差し替えた結果は、mktemp
で一時ファイルを作ってそこに出力します。Pandocにはその一時ファイルを渡します。
具体的な方法は、まず、取り出しておいたタイトルを% $title
の形式で1行目に書き出し、続けて元のファイルの2行目から出力します。
「2行目から出力」というところは、AWK先生にお願いしたら、2<=NR
でできるそうです。
AWKは、テキストファイルをレコードとして操作するときにとても便利ですね。今までスクリプト言語で何とかしてしまうことが多かったから、全然使いこなせていません。
indexファイル
indexファイル(index.html
)には、集めた情報をリスト形式で出力します。
ここでは、HTMLファイルパス(a
タグに使用)、タイトル、最終更新日時を出力しています。
また、generator
情報をmeta
タグとコンテンツの両方に出力しています。
スタイルシート
スタイルシートは、./style.css
にしています。好きなスタイルシートを置きましょう。
私は、下記をお借りしてきました。ちょっとだけカスタマイズして使っています。
https://gist.github.com/dashed/6714393/
GitHub-like CSS for pandoc standalone HTML files (perfect for HTML5 output).
その他
上記以外には特に説明は必要ないと思いますが、ちょっとだけ補足。
ファイルの順番は、ls -t
を使って最終更新日時の新しい方から取得するようにしています。
今回の処理には複雑な分岐がありませんので、if
文を使わずに短絡評価(&&
,||
)だけで処理しています。
実行結果
変換するMarkdownファイルは、今回の記事自体です。
結果イメージは冒頭にある通りです。
- 入力の一部(今回の記事)
# シェルスクリプトとPandocでMarkdownをまとめてHTMLに変換してindexファイルも作る カテゴリー: Unix-like シェルスクリプトとPandocを使ってMarkdownをまとめてHTMLに変換します。 それだけでは芸がありませんので、「シェルスクリプトだけ(`sed`,`awk`は使う)」「indexファイルも作る」のところでちょっとだけ工夫をしています。 --- ## 環境
- スクリプトの実行結果
$ markdown-to-html-with-gen-index ./markdowns . "markdown-to-html-with-gen-index" - MarkdownをまとめてHTMLに変換してindexファイルも作る HTMLファイルの生成を開始. 変換: 20170427-htmlgen-from-md-with-sh-and-pandoc.md -> 20170427-htmlgen-from-md-with-sh-and-pandoc.html ..... 完了 変換: 20170410-java-game-maze.md -> 20170410-java-game-maze.html ..... 完了 変換: 20170405-python-2017-winter.md -> 20170405-python-2017-winter.html ..... 完了 変換: 20170406-python-1st-year.md -> 20170406-python-1st-year.html ..... 完了 変換: 20170403-iPhone-barcode-reader.md -> 20170403-iPhone-barcode-reader.html ..... 完了 変換: 20170328-java-firefox-history-dump.md -> 20170328-java-firefox-history-dump.html ..... 完了 完了しました. $
あとがき
最近は再びシェルスクリプトをいじることが多くて、遊んでいたらこんなの出来たので公開してみました。
シェルスクリプトは、堅いプログラミングには向きませんが、小規模のツールを作るには覚えておくと便利ですね。
あと、今回はPandocがあってこその成果でもあります。
(おわり)