Intereting Posts
FreeNAS: моментальные снимки на реплицированных наборах данных исчезают Shell Script для поиска разделов Windows и замены рабочего изображения Если Linux является только kernelм, то как использовались его первые версии (без распространения)? Уменьшите пространство вокруг линейных формул в LibreOffice WLAN подключен, но нет доступа в Интернет Почему пространство массива Raid 5 не равно сумме дисков? Может ли ядро ​​удалить исходящий пакет, который был захвачен tcpdump? Как использовать резервную копию в OpenVZ Почему моя включенная система systemd не запускается при загрузке? Нужно ли мне * `exit 0` в конце` rc.local`? Повторное кодирование видео с помощью ffmpeg, включая все субтитры, но не все аудио Кошка в фило не бежит через баш Безопасно ли удалять все разделы подкачки? Экспорт сертификатов контактов в Evolution Почему субволок верхнего уровня по умолчанию (id = 5) не показан в списке subvolume btrfs -a?

sed на cygwin может заменить только одного персонажа?

Я пытаюсь заменить элемент XML в 20+ файлах в Windows с помощью sed и cygwin. Линия:

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" 

Вышеизложенное ничего не делает. Что я делаю не так? Является ли шеврон особым персонажем или я злоупотребляю sed? Или это вина в cygwin?

Скорее всего, этот файл кодируется в UTF-16, то есть с 2 или 4 байтами на каждый символ, возможно, даже с байтом-порядком-знаком в начале.

Символы, которые показаны в вашем примере (все символы ASCII), обычно кодируются по 2 байтам, первая или вторая из которых (в зависимости от того, является ли это кодировкой большого UFF-16 с большой энфией или малой величиной) равной 0, а другая являющийся кодом ASCII / Unicode. Байт 0, как правило, невидим на терминале, так что текст появляется ОК, когда он сбрасывается там, так как остальное является просто ASCII, но в действительности текст содержит:

 <[NUL]S[NUL]t[NUL]a[NUL]r[NUL]t[NUL]W[NUL]h[NUL]e[NUL]n[NUL]... 

Вам нужно будет преобразовать этот текст в charset вашей локали для 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 

Это предполагает, что на входе есть спецификация. Если нет, вам нужно определить, является ли он большим endian или little endian (возможно, немного endian), и измените это utf-16 на utf-16le или utf-16be .

Если кодировка locale UTF-8, в переводе не должно быть ничего потерянного, даже если текст содержит символы, отличные от ASCII.

Поскольку sed Cygwin обычно является 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. Вы можете использовать sed -nl или od -tc чтобы увидеть скрытые символы NUL. Пример малоинтенсивного текста 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 -nl \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 

Поместите команду sed в файл, например, sed.cmds, а затем вызовите sed как:

 sed -i -f "sed.cmds" "MyFile.xml" 

Также попробуйте изменить разделитель на _ , например:

s_<BooleanTag>true</BooleanTag>_<BooleanTag>false</BooleanTag>_g