속성과 버전이 다른 JSON 파일이 꽤 많이 있습니다. 특정 조건과 일치하는 파일만 수정하고 싶습니다. 후속작입니다find 및 jq를 사용한 내부 편집.
수백 개의 파일을 수정하고 PR을 열면 변경하고 싶은 것 외에는 아무것도 필요하지 않기 때문에 이것이 나에게 중요합니다. 예를 들어 들여쓰기를 변경하면 전체 파일이 변경된 것처럼 나타나 검토자가 실제 차이점을 확인하기 어렵습니다.
무슨 뜻인지 설명하기 위해 다음 두 파일을 이름이 지정된 폴더에 넣습니다 json
.
{
"identifier": "1",
"version" : "1.0"
}
버전 뒤의 공백을 참고하세요. 이는 의도적인 것입니다.
{
"identifier": "2",
"version": "2.0"
}
이 조각의 들여쓰기는 공백 4개입니다(vscode의 기본값).
json 폴더를 가리키는 다음 스크립트를 실행합니다.
find json \
-name '*.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 {} +
내가 원하는 결과는 를 2.0
제외한 버전의 파일만 수정된다는 것입니다 identifier
. 최종 결과는 다음과 같습니다.
첫 번째 파일에는 원래 식별자(예상)가 있지만 들여쓰기가 이제 2개의 공백(예기치 않음)이고 다음 공백이 version
사라졌습니다(예기치 않음).
{
"identifier": "1",
"version": "1.0"
}
두 번째 파일에는 빈 식별자(예상)가 있고 들여쓰기는 이제 2개의 공백입니다(예상치 않음).
{
"identifier": "",
"version": "2.0"
}
내가 아는 한 jq는 들여쓰기를 유지할 수 없으므로 질문의 범위를 제한하기 위해 일치하지 않는 버전의 파일을 영향을 받지 않게 유지하는 방법에만 관심이 있습니다.
grep
위에 링크된 질문의 답변을 결합하여 이 문제를 해결 했지만 jq만 사용하는 더 효율적인 방법이 있을까요? 가능한 경우 원본 파일의 들여쓰기를 모두 유지하는 것이 이점입니다.
find json \
-name '*.json' \
-type f -exec sh -c '
for pathname do
if grep "\"version\": \"2.0\"" "$pathname" 1> /dev/null; then
tmpfile=$(mktemp)
cp -- "$pathname" "$tmpfile" &&
jq "select(.version == \"2.0\").identifier |= \"\"" <"$tmpfile" >"$pathname"
rm -f "$tmpfile"
fi
done' sh {} +
답변1
grep
JSON 파일에서는 다음을 사용할 수 있습니다.일하다, 그러나 예상되는 형식의 파일에 따라 다릅니다. 또한, 일반적인 JSON 문서에서는 키의 순서가 고정되어 있지 않다는 점을 고려하면, identifier
버전을 파악하면서 키의 null이 아닌 값을 테스트하는 것도 중요하다. 2.0
그렇습니다. jq
이 목적으로 사용하는 것이 가장 좋습니다.
이 작업은 변경해야 하는 JSON 파일에만 적용됩니다. 이 파일에는 version
값이 있으며 2.0
비어 identifier
있지 않습니다.
를 사용하면 -e
마지막 jq
으로 평가된 표현식이 제공한 종료 상태로 종료할 수 있으며, 이를 사용하여 현재 파일이 수정될 것인지 여부를 테스트할 수 있습니다. 다음을 사용하여 any()
선택한 입력 객체에 null이 아닌 값이 있는지 확인할 수 있습니다 identifier
.
jq -e 'any(select(.version == "2.0"); .identifier != "")'
현재 JSON 문서에 수정이 필요한 경우 종료 상태가 0("성공")으로 종료됩니다.
명령의 일부로 find
:
find json \
-name '*.json' \
-type f -exec sh -c '
tmpfile=$(mktemp)
for pathname do
if jq -e "any(select(.version == \"2.0\"); .identifier != \"\")" "$pathname" >/dev/null
then
cp -- "$pathname" "$tmpfile" &&
jq "select(.version == \"2.0\").identifier |= \"\"" <"$tmpfile" >"$pathname"
fi
done
rm -f "$tmpfile"' sh {} +
어떤 파일이든 참고해주세요예두 번째 통화는 jq
다음으로 변경됩니다.고쳐 쓰기, 이는 identifier
키 값 외에도 파일의 들여쓰기 및 기타 공백을 변경할 수 있음을 의미합니다. 파서의 관점에서 이는 JSON 문서에 영향을 미치지 않지만 JSON을 지원하지 않는 도구에서 보고된 파일에 대한 추가 변경을 유발할 수 있습니다.
--indent 4
공백 4개를 들여 쓰기하여 JSON을 작성하려면 jq
.