Да, вроде официально:
https://lists.centos.org/pipermail/centos-announce/2015-October/021430.html
Во избежание путаницы я бы посоветовал вам использовать разделитель, отличный от /
, для sed
, если /
присутствует в ваших паттернах. Я лично использую ~
для таких случаев. Тот -лайнер, который вам нужен, выглядит так:
sed '/<FilePath>/s~/~\\~g;/<\\FilePath>/s~<\\~</~' your_file
Пояснение :/<FilePath>/s~/~\\~g
-заменяет /
на \
в строках, содержащих подстроку <FilePath>
. Это заменит все /
, так что </FilePath>
станет <\FilePath>
. Чтобы вернуть это, нужна вторая часть выражения-/<\\FilePath>/s~<\\~</~
Вот довольно простое решение, созданное с помощью конвейера с использованием sed и tr. Предполагается, что:
<FilePath>…</FilePath>
(нет вложенных тегов, замена выполняется только до следующего <
после<FilePath>
). <FilePath>
не появляется внутри литеральной строки (нет <![CDATA[<FilePath>/blah]]>
или<mytag label="<FilePath>">
). Принцип заключается в использовании tr
для переключения между <
и разрывами строк; таким образом, когда sed обрабатывает «строку», он фактически обрабатывает текст между одним тегом открытия/закрытия и текстовым тегом открытия/закрытия.
tr '<\n' '\n<' | sed '/^FilePath>/ y:/:\\:' | tr '<\n' '\n<'
Вот Perl-решение. Предполагается, что:
<FilePath>…</FilePath>
. <FilePath>
не появляется внутри литеральной строки (нет <![CDATA[<FilePath>/blah]]>
или<mytag label="<FilePath>">
). <FilePath>
всегда следует </FilePath>
в той же строке ).Конструкция довольно естественна :она применяет функцию backslashify
к тексту внутри <FilePath>…</FilePath>
. Регулярное выражение .*?
— это не -жадное совпадение :, жадное совпадение .*
заменит все от первого <FilePath>
до последнего </FilePath>
в строке, если в строке будет несколько <FilePath>…</FilePath>
фрагментов. та же линия. s:(?!<<)/(?!>):\\:
— это более изящная версия tr:/:\\:
, которая позволяет избежать замены косых черт, если они идут непосредственно перед >
или после <
, что позволяет использовать вложенные теги.
perl -pe 'sub backslashify {local $_ = $_[0]; s:(?!<<)/(?!>):\\:; return $_} s:(<FilePath>)(.*?)(</FilePath>):$1.backslashify($2).$3:e'
команда
sed -e 's/\//\\/g' -e 's/<\\/<\//g' filename
выход
<FilePath>a\b\c\d</FilePath>
<OtherTags>Bob</OtherTags>
<FilePath>1\2\3\4</FilePath>
С GNU awk для соответствия 3-го аргумента():
awk 'match($0,/(.*<FilePath>)(.*)(<\/FilePath>.*)/,a){ gsub("/","\\",a[2]); $0=a[1] a[2] a[3] } 1' file
<FilePath>a\b\c\d</FilePath>
<OtherTags>Bob/Smith</OtherTags>
<FilePath>1\2\3\4</FilePath>
Вышеописанное было выполнено с использованием этого ввода:
$ cat file
<FilePath>a/b/c/d</FilePath>
<OtherTags>Bob/Smith</OtherTags>
<FilePath>1/2/3/4</FilePath>
В GNU sed с расширенным режимом регулярных выражений мы можем постепенно сопоставлять открытие и закрытие тега xml FilePath в одной и той же строке и предполагать, что этот тег не является частью кавычек или комментариев.
sed -Ee ' :a;s|<(FilePath)>([^/]*(/[^/]*)*)/([^/]*</\1>)|<\1>\2\\\4|;ta' file
perl -lpe '
s{<FilePath>\K.*?(?=</FilePath>)}
<$& =~ tr|/|\\|r>xge;
' file
Мы изолируем часть между открытием и закрытием тега и преобразуем прямая косая черта на обратную косую черту в его части.
Мы можем составить многострочное регулярное выражение для простоты выражения намерения.
snr='
s|
<(FilePath)>
( [^/]* ([/][^/]*)* )
/
( [^/]* )
</\1>
|<\1> \2 \\ \4 </\1>|
'
ws=$'\t \n'
sed -E ":a;${snr//[$ws]/};ta" file
Предполагая, что документ является правильно сформированным XML-документом, таким как
<?xml version="1.0"?>
<root>
<FilePath>a/b/c/d</FilePath>
<OtherTags>Bob</OtherTags>
<FilePath>1/2/3/4</FilePath>
</root>
Затем, используя xmlstarlet
, мы можем преобразовать прямую косую черту в обратную косую черту в значениях всех FilePath
узлов:
$ xmlstarlet ed -u '//FilePath' -x 'translate(., "/", "\")' file.xml
<?xml version="1.0"?>
<root>
<FilePath>a\b\c\d</FilePath>
<OtherTags>Bob</OtherTags>
<FilePath>1\2\3\4</FilePath>
</root>
Функция XPath translate()
изменяет символы второго аргумента(/
)на символы третьего аргумента(\
)в строке, на которую ссылается первый аргумент (.
, значение текущего узла ). Функция translate()
применяется ко всем узлам, соответствующим XPath //FilePath
. Этот шаблон XPath соответствует узлам FilePath
в любом месте всего документа.