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가 없는 모든 항목을 삭제한다는 의미입니다 .verison
2.0
2.0
version
대신 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 {} +