如何在文本文件中的特定模式后替换请求值?

时间:2019-01-26 13:40:06

标签: xml bash shell unix sed

Solaris,版本:11.10.0,版本= 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

任何帮助将不胜感激。

3 个答案:

答案 0 :(得分: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>

一种非常简单的方法,如果您测试正常并且想要就地更改文件,请添加-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,这是一种避免在封闭标签(IE /)中逃脱s#from#to#;的简便方法。
这很简单,所以我认为您不会遇到困难:)
添加-i开关以进行就地更改,例如:perl -i -pe '...

答案 1 :(得分:1)

$ 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>

首先用">333 "否定其中具有/.*333 /!的字符串。这样的字符串将受到第二个正则表达式s#^(\s*<[^>]+>).*(</[^>]+>)$#\133333\2#;的影响。确实包含">333 "的字符串将根据s|^(\s*<[^>]+>333 ).*(</[^>]+>)$|\133333\2|进行更改。

在sed中添加-i选项以应用更改。

编辑:

正如@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选项将所做的更改应用于文件。

答案 2 :(得分:1)

张贴所有正确的详细信息,以供将来的用户使用:

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

以上将用333333333替换所有标记值,即使不是AccountNumber,BranchNumber..etc标记,也将替换其他标记值。另外NameAndCity和OwnerFullName是字母数字,因此我们需要为Regex添加字母数字/特殊/空格。这是答案:

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