JavaScriptを有効にしてください

[Hugo] 自動投稿したい2(ファイル抽出と更新)

 ·  ☕ 4 分で読めます

公開可能な記事を抽出して日付を更新する

hugo list futureを使用することで、将来公開されるであろう記事一覧を抽出できた。 詳細はこちら
今回は一覧から更新日時が最も古いものを抽出して、日付を公開日(処理実行日)にする。

前提

  • hugo v0.96.0+extended
  • macos 12.5
  • 公開予定の記事のフロントマター
    • date: 9999-12-31T00:00:00+09:00
    • draft: false

コマンド

最終形

$ hugo list future | cut -d ',' -f 1 | xargs -r ls -tr | head -n 1 | xargs -r sed -i "s/9999-12-31T00:00:00+09:00/$(TZ=Asia/Tokyo date -Iseconds)/" 

こんな感じで実行すると公開予定の記事の中で、更新日時が古い記事のフロントマターを処理日時に更新できた。

※ローカルではこれでよかったけど、本番ではlsを使用してソートするのはできなかったので、最終的には違う形になった。
詳細はこちら

cutコマンド

最初の出力がこれ

❯ hugo list future
content/ja/posts/hoge.md,9999-12-31T00:00:00+09:00
content/ja/posts/hoge3.md,9999-12-31T00:00:00+09:00

ここからファイルパスだけをxargsに渡したい
man cutより抜粋

-d delim
Use delim as the field delimiter character instead of the tab character.

-f list
The list specifies fields, separated in the input by the field delimiter character (see the -d option). Output fields are separated by a single occurrence of the field delimiter character.

オプションを指定することで,で区切られた最初の列を取り出せる

❯ hugo list future | cut -d ',' -f 1 
content/ja/posts/hoge.md
content/ja/posts/hoge3.md

lsコマンド

man lsより抜粋

-t Sort by descending time modified (most recently modified first). If two files have the same modification timestamp, sort their names in ascending lexicographical order. The -r option reverses both of these sort orders.

-r Reverse the order of the sort.

-tオプションで更新日時が新しい順に並び、-rオプションで逆順になる。
対象については前述のcutで出力されたファイル群を使用するので、xargsと併用する。

xargsコマンド

参考
https://linuxjm.osdn.jp/html/GNU_findutils/man1/xargs.1.html

xargs は、 標準入力から空白や改行で区切られた一連の項目を読み込み (空白はダブルクォート、 シングルクォート、 バックスラッシュによって保護できます)、 これを引数にして、 指定した command を 1 回以上実行する (デフォルトのコマンドは echo です)

今回だとcutの実行結果として、ファイルパスが改行で区切られていて、それらを引数にしてlsを実行する。

❯ hugo list future | cut -d ',' -f 1 | xargs -r ls -tr
content/ja/posts/hoge.md        content/ja/posts/hoge3.md

※ローカル(mac)で実行した時には-rは使用していなくても特に問題にならなかったが、Github Actionsのubuntuで実行する時には挙動が変わった。
公開できる記事がない場合はxargsまでの結果が空になるため、-rを指定しない場合には引数なしでlsを実行するようになり、プロジェクトのルートディレクトリを対象とした場合の結果となってしまった。
そのため標準入力が空の場合にはlsを実行しないようにオプションをつける必要があった。

headコマンド

man headより抜粋

-n count, –lines=count
Print count lines of each of the specified files.

一行目だけを取り出す。この時点で公開対象記事の抽出が完了する。
あとは前述のxargsに渡して、文字列の置き換えを行うことで日付を更新する。

❯ hugo list future | cut -d ',' -f 1 | xargs -r ls -tr | head -1
content/ja/posts/hoge.md

sedコマンド

引数に渡したファイルに対して一括置換処理ができる。
これも環境により挙動が違う部分があり、ローカルとGithub Actionsでは同じ記述ではうまく動作できなかった。
xargs以前の部分は同じで、上に記載した各コマンドを実行した結果を渡している
Github Actions(ubuntu)

xargs -r sed -i "s/9999-12-31T00:00:00+09:00/$(TZ=Asia/Tokyo date -Iseconds)/"

ローカル(mac)

xargs -r sed -i "" "s/9999-12-31T00:00:00+09:00/$(TZ=Asia/Tokyo date -Iseconds)/" 

sedコマンドの種類と対処法についてはこちらに記載されていた。
https://it-ojisan.tokyo/mac-linux-sed/

置換部分の指定はルールを変えたら修正する必要があるけど、基本的に変えないと思う。
(各コマンドの挙動が変わったら対応する必要がある)

dateコマンド

man dateより抜粋

The command

TZ=America/Los_Angeles date -Iseconds -r 1533415339

will display

2018-08-04T13:42:19-07:00

上記のような表示例があったので、それを参考にした。
タイムゾーンを指定して実行することで、それに合う日時が表示される

❯ TZ=Asia/Tokyo date -Iseconds
2023-01-02T14:20:57+09:00

❯ TZ=America/Los_Angeles date -Iseconds
2023-01-01T21:21:11-08:00

sedの置換で使用し、フロントマターのdateを日本時間の処理日時に合わせることで公開日と記事に記載されている日付を一致させる。

その他

とりあえず意図する状態をシェルスクリプトで再現できた。
hugo listを使用せずにgrep等でもできそうだが、draftdateで判定してくれるので使用した方が便利だった。
あとはこれをGithub Actionsで動かし、変更をコミット、プッシュする。


書いた人
keee
Webエンジニア

目次