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 {} +

관련 정보