SED命令删除2个标签之间的正斜杠“/”

SED命令删除2个标签之间的正斜杠“/”

我使用的是 Linux,我想用它来删除2 个标签之间的sed正斜杠 ( )。/由此:

<file>/text</file>
<file>/text2</file
<file>/text</file>..

对此

<file>text</file>
<file>text2</file
<file>text</file>..

测试了很多代码没有成功示例:

sed s'/<file>/s|^\.{1,2}/||' fileout

你能帮我吗?

答案1

给定一个格式良好的 XML 文件,例如

<?xml version="1.0"?>
<root>
  <file>/text</file>
  <file>/text2</file>
  <file>/text</file>
  <file>other text</file>
</root>

file...如果值以 开头,您可以使用 XMLStarlet 删除每个节点值的第一个字符/

xmlstarlet edit \
    --update '//file[starts-with(text(), "/")]' \
    --expr 'substring(text(), 2)' \
    myfile.xml

或者,使用更短的语法,

xmlstarlet ed \
    -u '//file[starts-with(text(), "/")]' \
    -x 'substring(text(), 2)' \
    myfile.xml

这将查找file整个输入文档中值以 开头的每个节点/,然后使用 删除该第一个字符substring()

结果:

<?xml version="1.0"?>
<root>
  <file>text</file>
  <file>text2</file>
  <file>text</file>
  <file>other text</file>
</root>

这(以及下面的)将处理其值包含嵌入换行符的节点。


您是否想检测/值中的任何位置,而不仅仅是在开始处,如果您想将它们全部删除,您可以使用contains()andtranslate()来代替:

xmlstarlet edit \
    --update '//file[contains(text(), "/")]' \
    --expr 'translate(text(), "/", "")' \
    myfile.xml

或者只是(因为如果其中translate()没有值,调用将使值保持不变),/

xmlstarlet edit \
    --update '//file' \
    --expr 'translate(text(), "/", "")' \
    myfile.xml

给定这个输入文件:

<?xml version="1.0"?>
<root>
  <file>text/</file>
  <file>/text/2</file>
  <file>te/x/t/</file>
  <file>other text</file>
</root>

...上面的命令将产生以下结果:

<?xml version="1.0"?>
<root>
  <file>text</file>
  <file>text2</file>
  <file>text</file>
  <file>other text</file>
</root>

答案2

输入(固定语法)XML文件(错过了>第二个节点的关闭file):

<r>
<file>/text</file>
<file>/text2</file>
<file>/text</file>
</r>

具有现代语法和正确的XPath功能fn:replace()(有点sedfor XPath,允许使用正则表达式和捕获组版本XPath>= 2),使用XQuery,您可以执行以下操作:

xidel --xquery '
    <r>{
        for $x in //file
        return <file>{replace($x, "^/(.*)", "$1")}</file> 
    }</r>
' --output-format=xml file.xml

得出:

<?xml version="1.0" encoding="UTF-8"?>
<r>
<file>text</file>
<file>text2</file>
<file>text</file>
</r>

如果您需要即时编辑文件,请使用sponge以下工具GNU more-utils

xidel ... file.xml | sponge file.xml

答案3

如果输入的每一行只有两个正斜杠,您可以尝试以下 awk 命令:

$ awk  'BEGIN{OFS=FS="/"}{printf "%s", $1;print$2,$3}' input_file
<file>text</file>
<file>text2</file
<file>text</file>

您需要根据要删除的正斜杠重新定位 printf 和 print 。

答案4

使用(以前称为 Perl_6)

...使用 Raku 的(社区支持的)XML模块:

~$ raku -MXML -e 'my  $xml = open-xml( $*ARGFILES.Str );
                  for $xml.elements( :RECURSE(0), :TAG{"file"} ) -> $E {
                      my $old = $E.contents[0];
                      my $new = XML::Text.new( text => $old.text.subst(/^ "/" /) );
                      $E.replace( $old, $new );
                  };  .say for $xml;'   file.xml

Raku 是 Perl 家族中的一种编程语言,具有高级功能语法用于解析文本。上面使用了它的原生XML语法引擎,Raku的面向对象XML模块解析输入XML文件。 XML 元素因此被识别并且可以被迭代。

仅正则表达式(例如sed)解决方案的一个问题XML是替换往往是混杂的:您通常很难将替换限制为仅限于某些深度/标签。在带有 -module 的 Raku 中XML,您可以(例如)将替换限制为 1)。顶层和 2)。仅在<file>TAG 内。这是通过将代码设置为在elements限制条件下进行迭代来完成的:RECURSE(0), :TAG{"file"}。在这里,:NEST也可以添加 来仅迭代EVEN节点。

[如果您想迭代所有TAG深度的所有 s,不用担心:只需设置:RECURSE(Inf)和删除:TAG命名参数,这会将:TAG限制设置为 False ]。

这样就确定了,每个元素的内部(即非TAG)contents[0]都被赋值给变量$old,它实际上是一个XML::Text对象。该$old对象被.text提取到一个字符串中,并且subst没有任何内容来删除有问题的"/"正斜杠。使用现已更正的键/值对XML::Text.new创建 ( )新的 ( ) 对象。从这里开始,-module 的例程完成了工作:。$newtext => 'value'XMLreplacereplace( $old, $new )

输入示例(感谢@Kusalananda!):

<?xml version="1.0"?>
<root>
  <file>/text</file>
  <file>/text2</file>
  <file>/text</file>
  <file>other text</file>
</root>

示例输出(前导 -/已从 <file> 标记中删除):

<?xml version="1.0"?><root>
  <file>text</file>
  <file>text2</file>
  <file>text</file>
  <file>other text</file>
</root>

https://github.com/raku-community-modules/XML
https://raku.land/?q=XML
https://rakudo.org/
https://raku.org

相关内容