cygwin의 sed는 하나의 문자만 대체할 수 있습니까?

cygwin의 sed는 하나의 문자만 대체할 수 있습니까?

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-16leutf-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 -tcBOM이 포함된 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여러 파일을 처리하려면:bashksh93

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

관련 정보