Intereting Posts
Для цикла не работает в функции с аргументами Как перезапустить приложение, контролируемое monit в определенное время poweroff nvidia gpu Возможно ли монтировать файловые системы Windows без использования учетной записи root? Force OpenSSH / pam / pam_ldapd для выполнения pam_ldapd (sshd: auth) с аутентификацией с открытым ключом Драйверы Realtek предотвращают обнаружение интерфейса eth1? Fedora 23: «обновление dnf» застряло в «Выполнение транзакции» Как обновить с Debian 8 Jessie до Debian 9 Stretch? Можем ли мы настраивать разные оболочки для разных пользователей в одном дистрибутиве Linux / Unix? дважды запустите make install Как я могу уничтожить репозиторий git, достаточно быстро? awk: установить желаемое количество столбцов? Как поместить завершенные загрузки в каталог с помощью aria2c? хотите скопировать несколько файлов * .txt из нескольких каталогов в один и тот же каталог, но переименуйте новый файл Преобразовать вывод терминала tty в обычный текст

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