やりたいこと
GithubActions上でJSONを書き換えるのにいい方法ないかなーと思ったことです。
console
% echo '[{"name":"hoge","age":"29"},{"name":"fuga","age":"30"}]' > test.json
% cat test.json | jq
[
{
"name": "hoge",
"age": "29"
},
{
"name": "fuga",
"age": "30"
}
]
% jq '.[1].age="25"' test.json # この結果でtest.jsonを上書きたい
[
{
"name": "hoge",
"age": "29"
},
{
"name": "fuga",
"age": "25"
}
]
できない方法
console
% cat test.json | jq '.[1].age="25"' > test.json
% cat test.json | jq # 空ファイルになる
シェルがコマンドラインを解釈した後、hoge.txt をオープンして 0 バイトにしてから cat を起動するので当然の結果です。実行したいコマンドラインの前に hoge.txt を一時ファイルにコピーして利用するか、実行結果を一時ファイルに出力したあと上書きする必要があります。
リダイレクトはコマンドが実行される前に shell が処理してしまってますから、コマンドが実行された時には既にファイルは空になっています。
簡単にできるわけではなさそう。
実現する方法
1.tmpを作って逃がす
違う名前だったら処理結果を出力できるので
console
% echo '[{"name":"hoge","age":"29"},{"name":"fuga","age":"30"}]' > test.json
% jq '.[1].age="25"' test.json > tmp && mv tmp test.json
% cat test.json | jq
[
{
"name": "hoge",
"age": "29"
},
{
"name": "fuga",
"age": "25"
}
]
2.黒魔術
悪くはなさそうだけど、何をやってるのか直感的じゃないですね。。。
console
% echo '[{"name":"hoge","age":"29"},{"name":"fuga","age":"30"}]' > test.json
% (rm test.json && jq '.[1].age="25"' > test.json) < test.json
% cat test.json | jq
[
{
"name": "hoge",
"age": "29"
},
{
"name": "fuga",
"age": "25"
}
]
3. sponge
macOSなら brew install moreutils
した後で
console
% echo '[{"name":"hoge","age":"29"},{"name":"fuga","age":"30"}]' > test.json
% jq '.[1].age="25"' test.json | sponge test.json
% cat test.json | jq
[
{
"name": "hoge",
"age": "29"
},
{
"name": "fuga",
"age": "25"
}
]
後から読む人のことを考えたら1が良さそうです。
3はスッキリするけど、この為だけにインストールしなきゃなので…