【问题标题】:How to replace a Request value after a specific pattern in text file?如何在文本文件中的特定模式之后替换请求值?
【发布时间】:2019-06-20 02:13:43
【问题描述】:

Solaris,版本:11.10.0,REV=2005.01.21.15.53
我有一个文件test.txt,其中包含如下值:

 <Info>
     <AccountNumber>23456789</AccountNumber>
     <BranchNumber>004</BranchNumber>
     <TransitNumber>01646</TransitNumber>
     <NameAndCity>XYZ Bank</NameAndCity>
     <OwnerFullName>ABC XYZ</OwnerFullName>
  </Info>

所有信息都在一行中,我们有多个行,如上所示,还有其他标签可用。

它还包含其他标记值。此外,如果标签值包含“333”组合,我不想替换它们。

我想使用 sed 命令将标签的值替换为 33333,替换后,我想将更新后的信息保存到同一个文件中。
输出应该是:

 <Info>
     <AccountNumber>33333333</AccountNumber>
     <BranchNumber>33333</BranchNumber>
     <TransitNumber>3333333</TransitNumber>
     <NameAndCity>333 33333</NameAndCity>
     <OwnerFullName>3333 33333</OwnerFullName>
  </Info>

我是 shell 脚本的新手,不能完全编写模式来匹配它。

这是我迄今为止对前两个标签值实施的,但它不起作用:

sed 's/(<AccountNumber>)\+[0-2,4-9]*$/\1 33333333/' test.txt
sed 's/(<BranchNumber>)\+[0-2,4-9]*$/\1 33333/' test.txt

任何帮助将不胜感激。

【问题讨论】:

  • 实际标签为:2345678234
  • 感谢 Tiw,已更新
  • 啊...我以为你只想替换两个标签,但编辑后我看到你想替换所有标签中的值?
  • Solaris,版本:11.10.0,REV=2005.01.21.15.53

标签: xml bash shell unix sed


【解决方案1】:

试试这个:

sed -e '/333/!{' -e 's#<AccountNumber>[0-9]*</AccountNumber>#<AccountNumber>333333333</AccountNumber>#;s#<BranchNumber>[0-9]*</BranchNumber>#<BranchNumber>33333</BranchNumber>#;}'

例如:

$ sed -e '/333/!{' -e 's#<AccountNumber>[0-9]*</AccountNumber>#<AccountNumber>333333333</AccountNumber>#;s#<BranchNumber>[0-9]*</BranchNumber>#<BranchNumber>33333</BranchNumber>#;}'  test.txt
 <Info>
     <AccountNumber>333333333</AccountNumber>
     <BranchNumber>33333</BranchNumber>
     <TransitNumber>01646</TransitNumber>
     <NameAndCity>XYZ Bank</NameAndCity>
     <OwnerFullName>ABC XYZ</OwnerFullName>
  </Info>

一个很直接的方法,如果你测试ok,想原地改文件,加-i开关。

我没有要测试的 Solaris,所以不能确定。

试试这个简单的perl 看看它是否有效:

perl -pe 's#<AccountNumber>[0-9]*</AccountNumber>#<AccountNumber>333333333</AccountNumber>#' test.txt

如果它工作正常,我们可以添加其他人。

所以对于你在问题中首先写的逻辑,应该是这样的:

perl -pe 'unless (/333/) {s#<AccountNumber>[0-9]*</AccountNumber>#<AccountNumber>333333333</AccountNumber>#;s#<BranchNumber>[0-9]*</BranchNumber>#<BranchNumber>33333</BranchNumber>#;}' test.txt

您可以自己添加其他替代品。 # 是替换s 的常用/,这是一种更简单的方法来避免在关闭标签中转义/(即s#from#to#;)。
这很简单,所以我认为你不会有任何困难:)
添加-i开关就地改变,像这样:perl -i -pe '...

【讨论】:

    【解决方案2】:
    $ cat file.txt 
    <Info>
        <AccountNumber>23456789</AccountNumber>
        <BranchNumber>004</BranchNumber>
        <TransitNumber>01646</TransitNumber>
        <NameAndCity>XYZ Bank</NameAndCity>
        <OwnerFullName>ABC XYZ</OwnerFullName>
    </Info>
    <Info>
        <AccountNumber>23456789</AccountNumber>
        <BranchNumber>004</BranchNumber>
        <TransitNumber>01646</TransitNumber>
        <NameAndCity>333 Bank</NameAndCity>
        <OwnerFullName>ABC XYZ</OwnerFullName>
    </Info>
    
    $ sed -r '/.*333 /!s#^(\s*<[^>]+>).*(</[^>]+>)$#\133333\2#;s|^(\s*<[^>]+>333 ).*(</[^>]+>)$|\133333\2|' file.txt
    <Info>
        <AccountNumber>33333</AccountNumber>
        <BranchNumber>33333</BranchNumber>
        <TransitNumber>33333</TransitNumber>
        <NameAndCity>33333</NameAndCity>
        <OwnerFullName>33333</OwnerFullName>
    </Info>
    <Info>
        <AccountNumber>33333</AccountNumber>
        <BranchNumber>33333</BranchNumber>
        <TransitNumber>33333</TransitNumber>
        <NameAndCity>333 33333</NameAndCity>
        <OwnerFullName>33333</OwnerFullName>
    </Info>
    

    首先将包含"&gt;333 " 的字符串与/.*333 /! 取反。此类字符串将受到第二个正则表达式s#^(\s*&lt;[^&gt;]+&gt;).*(&lt;/[^&gt;]+&gt;)$#\133333\2#; 的影响。包含"&gt;333 " 的字符串将根据s|^(\s*&lt;[^&gt;]+&gt;333 ).*(&lt;/[^&gt;]+&gt;)$|\133333\2| 进行更改。

    将 -i 选项添加到 sed 以应用更改。

    编辑:

    正如@Tiw 所说,最好使用 perl 而不是 sed:

    $ perl -pe 's#<([^>]+)>(?:(?!333).)*</\1>#<\1>333333333<\1>#;s#<([^>]+)>333 .*#<\1>333 3333</\1>#' -i file.txt
    <Info>
        <AccountNumber>333333333<AccountNumber>
        <BranchNumber>333333333<BranchNumber>
        <TransitNumber>333333333<TransitNumber>
        <NameAndCity>333333333<NameAndCity>
        <OwnerFullName>333333333<OwnerFullName>
    </Info>
    <Info>
        <AccountNumber>333333333<AccountNumber>
        <BranchNumber>333333333<BranchNumber>
        <TransitNumber>333333333<TransitNumber>
        <NameAndCity>333 3333</NameAndCity>
        <OwnerFullName>333333333<OwnerFullName>
    </Info>
    

    注意:-i 选项将更改应用于文件。

    【讨论】:

    • $ sed -r '/.*333 /!s#^(\s*]+>).*([^>]+>)$#\133333 \2#;s|^(\s*]+>333 ).*([^>]+>)$|\133333\2|' test.txt sed: 非法选项 -- r @Bayou
    • @minkuJha 啊,我看到了man sed。在 gnu-sed 中,-r 选项启用扩展的正则表达式。根据man regex,您已经有反向引用。不带 -r 选项可以试试吗?
    • 我也尝试了 -r 但结果相同: $ sed -r '/.*333 /!s#^(\s*]+>).*( [^>]+>)$#\133333\2#;s|^(\s*]+>333 ).*([^>]+>)$|\133333\2| ' test.txt sed: 非法选项 -- r @Bayou
    • 没错@Tiw,Solaris 没有 gnu-sed
    • @minkuJha 您尚未删除 sed 和正则表达式之间的 -r 选项。你会得到类似sed "&lt;regex&gt;" &lt;file&gt;的东西。
    【解决方案3】:

    为未来的用户发布所有正确的详细信息:

    perl -pe 's#<([^>]+)>(?:(?!333).)*</\1>#<\1>333333333<\1>#;s#<([^>]+)>333 .*#<\1>333 3333</\1>#' -i file.txt
    

    上面会将所有标签值替换为 333333333 即使不是 AccountNumber、BranchNumber..etc 标签,它也会替换其他标签值。 NameAndCity 和 OwnerFullName 也是字母数字的,所以我们需要为那些添加带有字母数字/特殊/空格的正则表达式。这是答案:

    perl -i -pe 'unless (/333/) {s#<AccountNumber>[0-9]*</AccountNumber>#<AccountNumber>33333333</AccountNumber>#;
            s#<BranchNumber>[0-9]*</BranchNumber>#<BranchNumber>33333</BranchNumber>#;
            s#<TransitNumber>[0-9]*</TransitNumber>#<TransitNumber>3333333</TransitNumber>#;
            s#<NameAndCity>[A-Za-z\ \-\+]*</NameAndCity>#<NameAndCity>333 33333</NameAndCity>#;
            s#<OwnerFullName>[A-Za-z/\/\ \+]*</OwnerFullName>#<OwnerFullName>3333 33333</OwnerFullName>#;}' test.txt 
    

    【讨论】:

    • @Tiw,你能接受我的回答以备将来参考吗?发现很少的问题,所以添加了所有细节的修改。
    猜你喜欢
    • 2021-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-07
    • 2013-11-13
    • 2013-06-23
    • 2017-11-03
    • 2011-09-08
    相关资源
    最近更新 更多