findとjqを使用した内部編集結果は一貫していません。

findとjqを使用した内部編集結果は一貫していません。

jqを使ってかなりの数のファイルを修正しようとしています。もしファイルには特定の値を持つ属性が含まれています。

find . \
    -name '*.configuration.json' \
    -type f -exec bash -c 'jq "select(.version == \"2.0\") | .identifier = \"\"" $0 | sponge "$0"' {} \;

だから私はここで実際に出力をリダイレクトする方法-execいいえリダイレクトされた出力を使用しますjq

上記のスクリプトは見つかったいくつかのファイルに対して機能しますが、他の場合はファイル全体を上書きし、何もしません。競合状態が原因で発生したようですが、この問題を解決する方法がわかりません。

私が直面できる他の落とし穴に対する助けやアドバイスをいただきありがとうございます。

ベストアンサー1

式の問題は、JSONオブジェクトのキーではないjq場合、オブジェクトが選択されず、オブジェクトが出力されないことです。これは実際にasがないすべてのアイテムを削除することを意味します。verison2.02.0version

代わりにidentifier各オブジェクトの値が更新versionされます2.0

jq 'select(.version == "2.0").identifier = ""'

キーは、オブジェクトから値を抽出せずに値を更新することです。

コードにあるものと同様の次のものを使用することもできます。

jq 'select(.version == "2.0") |= (.identifier = "")'

これは更新演算子を使用して|=選択したオブジェクトを更新しますselect()

そしてfind

find . -name '*.configuration.json' -type f -exec sh -c '
    tmpfile=$(mktemp)
    for pathname do
        cp -- "$pathname" "$tmpfile" &&
        jq "select(.version == \"2.0\").identifier = \"\"" <"$tmpfile" >"$pathname"
    done
    rm -f "$tmpfile"' sh {} +

また、インラインスクリプトを不必要に複数回呼び出すのを防ぎ、sh -cスクリプト内のループを介して元のファイルの権限と所有権を保持します。

または使用したい場合sponge(私は自分で試したことがないのでテストされていない例だと思います):

find . -name '*.configuration.json' -type f -exec sh -c '
    for pathname do
        jq "select(.version == \"2.0\").identifier = \"\"" "$pathname" |
        sponge "$pathname"
    done' sh {} +

おすすめ記事