sed와 cygwin을 사용하여 Windows에서 20개 이상의 파일에 있는 XML 요소를 바꾸려고 합니다. 라인은 다음과 같습니다
cd "D:\Backups\Tasks"
sed -i 's~<StartWhenAvailable>true</StartWhenAvailable>~<StartWhenAvailable>false</StartWhenAvailable>~g' "Task_01.xml"
이것은 어떤 것도 대체할 수 없습니다. 그러나 시도하면 다음과 같습니다.
sed 's~<~[~g' "Task_01.xml"
다음과 같이 출력됩니다.
[AllowHardTerminate>true[/AllowHardTerminate>
[StartWhenAvailable>true[/StartWhenAvailable>
[RunOnlyIfNetworkAvailable>false[/RunOnlyIfNetworkAvailable>
그러나 문자 하나만 추가하려고 하면 문서가 있는 그대로 출력됩니다.
sed 's~<B~[B~g' "Task_01.xml"
위에서는 아무 것도 수행되지 않습니다. 내가 뭘 잘못했나요? chevron은 특수 문자입니까, 아니면 sed를 잘못 사용하고 있습니까? 아니면 cygwin 버그인가요?
답변1
대부분의 경우 파일은 UTF-16으로 인코딩되어 문자당 2바이트 또는 4바이트이며 시작 부분에 바이트 순서 표시가 있을 수도 있습니다.
예제에 표시된 문자(모든 ASCII 문자)는 일반적으로 2바이트를 사용하여 인코딩됩니다. 여기서 첫 번째 또는 두 번째 바이트(big-enfian 또는 little-endian UTF-16 인코딩인지 여부에 따라)는 0이고 나머지 A 0은 ASCII/유니코드 코드. 0바이트는 일반적으로 터미널에 표시되지 않으므로 거기에 덤프하면 나머지는 단지 ASCII이기 때문에 텍스트는 괜찮아 보이지만 실제로는 텍스트에 다음이 포함됩니다.
<[NUL]S[NUL]t[NUL]a[NUL]r[NUL]t[NUL]W[NUL]h[NUL]e[NUL]n[NUL]...
sed
이 텍스트를 처리 하려면 해당 로캘의 문자 집합으로 변환해야 합니다 . UTF-16은 Unix 로케일의 문자 인코딩으로 사용할 수 없습니다. UTF-16을 문자 인코딩으로 사용하는 로케일을 찾을 수 없습니다.
iconv -f utf-16 < Task_01.xml |
sed 's~<StartWhenAvailable>true</StartWhenAvailable>~<StartWhenAvailable>false</StartWhenAvailable>~g' |
iconv -t utf-16 > Task_01.xml.out
입력에 BOM이 있다고 가정합니다. 그렇지 않은 경우 빅 엔디안인지 리틀 엔디안(아마도 리틀 엔디안)인지 확인하고 또는 utf-16
로 변경해야 합니다 .utf-16le
utf-16be
로케일의 문자 집합이 UTF-8이면 텍스트에 ASCII가 아닌 문자가 포함되어 있어도 번역 시 손실되는 내용이 없어야 합니다.
Cygwin은 sed
일반적으로 GNU이므로 sed
해당 유형의 이진 입력을 자체적으로 처리할 수도 있습니다(NUL 바이트가 포함되어 있으므로). 다음과 같은 작업도 수행할 수 있습니다.
LC_ALL=C sed -i 's/t\x00r\x00u\x00e/f\x00a\x00l\x00s\x00e/g' Task_01.xml
이 file
명령은 입력이 실제로 UTF-16인지 여부를 알려줄 수 있습니다. 숨겨진 NUL 문자를 사용 sed -n l
하거나 볼 수 있습니다. od -tc
BOM이 포함된 Little-endian UTF-16 텍스트 예:
$ echo true | iconv -t utf-16 | od -tc
0000000 377 376 t \0 r \0 u \0 e \0 \n \0
0000014
$ echo true | iconv -t utf-16 | sed -n l
\377\376t\000r\000u\000e\000$
\000$
$ echo true | iconv -t utf-16 | file -
/dev/stdin: Little-endian UTF-16 Unicode text, with no line terminators
//를 사용하여 zsh
여러 파일을 처리하려면:bash
ksh93
set -o pipefail
for file in ./*.xml; do
cp -ai "$file" "$file.bak" &&
iconv -f utf-16 < "$file.bak" |
sed 's~<StartWhenAvailable>true</StartWhenAvailable>~<StartWhenAvailable>false</StartWhenAvailable>~g' |
iconv -t utf-16 > "$file" &&
rm -f "$file.bak"
done
답변2
sed
명령을 sed.cmds라는 파일에 넣고 다음 sed
과 같이 호출합니다.
sed -i -f "sed.cmds" "MyFile.xml"
또한 다음과 같이 구분 기호를 로 변경해 보았습니다 _
.
s_<BooleanTag>true</BooleanTag>_<BooleanTag>false</BooleanTag>_g