用字符X更改两个字符串之间的文件中的字符串

时间:2016-08-12 06:21:56

标签: bash shell sed

我想用相等数量的X替换标签之间的值。例如

1

<Name> Jason </Name>
to
<Name> XXXXX </Name>

2。  (见无空间)

 <Name>Jim</Name>
 to
 <Name>XXX</Name>

3

<Name Jason /> 
to 
<Name XXXXX />`

4

<Name Jas />
to
<Name XXX />

开始标记,值和结束标记都可以有不同的行

5

<Name>Jim
</Name>
to
<Name>XXX
</Name>

6

<Name>
     Jim
       </Name>
to
<Name>
     XXX
       </Name>

7

  <Name
     Jim
       />
to
  <Name
     XXX
       />

8

<Name> Jason </Name> <Name> Ignacio </Name>
to
<Name> XXXXX </Name> <Name> XXXXXX </Name>

9

<Name> Jason Ignacio </Name>
to
<Name> XXXXX XXXXXXX </Name>
or
<Name> XXXXXXXXXXXXX </Name>

两者都很好

我尝试了这个,但它没有用

file=mylog.log
search_str="<Name>"
end_str="</Name>"
sed -i -E ':a; s/('"$search_str"'X*)[^X'"$end_str"']/\1X/; ta' "$file"

请告诉我如何在bash脚本中执行此操作....

更新

我也尝试了这个,但没有为6和7个案件工作。案例1至5工作。

sed -i -E '/<Name>/{:a; /<\/Name>/bb; n; ba; :b; s/(<Name>X*)[^X\<]/\1X/; tb; }' "$file"
sed -i -E '/<Name[[:space:]]/{:a; /\/>/bb; n; ba; :b; s/(<Name[[:space:]]X*)[^X\/]/\1X/; tb; }' "$file"

2 个答案:

答案 0 :(得分:3)

临时解决方案

这扩展了首次提供的产品。下面并处理案例1,2,5,6,8,9。它不处理存在一个或多个完整<Name>…</Name>条目以及没有匹配{{1}的起始<Name>的情况在同一行。坦率地说,我甚至不确定如何开始解决这个问题。

未处理的案例3,4,7不是有效的XML - 我也不相信它们是有效的HTML(或XHTML)。我相信它们可以通过类似(但更简单)的机制来处理完全</Name>版本所示的机制。我将此作为练习留给读者(请注意角色类中的<Name>…</Name> - 它需要成为<)。

/

script.sed

第一行&#39;跳过&#39;处理不包含/<Name>/! b /<Name>.*<\/Name>/{ : l1 s/\(<Name>[[:space:]]*\(X[X[[:space:]]*\)\{0,1\}\)[^X<[:space:]]\(.*[[:space:]]*<\/Name>\)/\1X\3/ t l1 b } /<Name>/,/<\/Name>/{ # Handle up to 4 lines to the end-name tag /<\/Name>/! N /<\/Name>/! N /<\/Name>/! N /<\/Name>/! N # s/^/ZZ/; s/$/AA/p # s/^ZZ//; s/AA$// : l2 s/\(<Name>[[:space:]]*\(X[X[[:space:]]*\)\{0,1\}\)[^X<[:space:]]\(.*[[:space:]]*<\/Name>\)/\1X\3/ t l2 } 的行(它们被打印并读取下一行)。接下来的6行是来自&#39;首次提供的剧本&#39;除了有一个<Name>跳到处理结束。

新部分是b代码。这将自己查找/<Name>/,/<\/Name>/,并连接最多4行,直到模式空间中包含<Name>。这两条注释行用于调试 - 它们让我可以看到被视为一个单元的内容。除了使用标签</Name>代替l2之外,其余部分与首次提供时完全相同 - l1正则表达式已经适应新行。

这是重型sed脚本,而不是我想要使用或维护的脚本。我会使用一个使用XML解析器的Perl解决方案(因为我比Python更了解Perl),但Python也可以通过适当的XML解析器完成工作。

sed

略微扩展的数据文件。

data

没有声称<Name> Jason </Name> <Name>Jim</Name> <Name> Jason Bourne </Name> <Name> Elijah </Name> <Name> Dennis </Name> <Name> Elijah Wood </Name> <Name> Dennis The Menace </Name> <Name>Elijah Wood</Name> <Name>Dennis The Menace</Name> <Name> Jason </Name> <Name> Jim</Name> <Name> Jim </Name> <Name> Jason Bourne </Name> <Name> Jason Bourne </Name> <Name> Elijah </Name> <Name> Dennis </Name> <Name> Elijah Wood </Name> <Name> Dennis The Menace </Name> <Name>Elijah Wood</Name> <Name>Dennis The Menace</Name> <Name> Jason </Name> to <Name> XXXXX </Name> 2. (see no space) <Name>Jim</Name> to <Name>XXX</Name> 3. <!--Name Jason /--> to <!--Name XXXXX /-->` 4. <!--Name Jas /--> to <!--Name XXX /--> starting tag, value and closing tag can all come in different line 5. <Name>Jim </Name> to <Name>XXX </Name> 6. <Name> Jim </Name> to <Name> XXX </Name> 7. <!--Name Jim /--> to <!--Name XXX /--> 8. <Name> Jason </Name> <Name> Ignacio </Name> to <Name> XXXXX </Name> <Name> XXXXXX </Name> 9. <Name> Jason Ignacio </Name> to <Name> XXXXX XXXXXXX </Name> or <Name> XXXXXXXXXXXXX </Name> 文件包含最少的案例;这是重复的。它包括问题的材料,除了非正统的&#39;像data这样的XML元素将转换为XML注释<Name Value />。映射实际上并不重要;开场部分与<!--Name Value /-->不匹配(并且尾部与<Name>不匹配),因此无论如何都不会处理它们。

输出

</Name>

首次提供

部分答案 - 但它说明了您面临的问题。处理案件1&amp;在问题2中,加上多字变体,您可以使用脚本:

$ sed -f script.sed data <Name> XXXXX </Name> <Name>XXX</Name> <Name> XXXXX XXXXXX </Name> <Name> XXXXXX </Name> <Name> XXXXXX </Name> <Name> XXXXXX XXXX </Name> <Name> XXXXXX XXX XXXXXX </Name> <Name>XXXXXX XXXX</Name> <Name>XXXXXX XXX XXXXXX</Name> <Name> XXXXX </Name> <Name> XXX</Name> <Name> XXX </Name> <Name> XXXXX XXXXXX </Name> <Name> XXXXX XXXXXX </Name> <Name> XXXXXX </Name> <Name> XXXXXX </Name> <Name> XXXXXX XXXX </Name> <Name> XXXXXX XXX XXXXXX </Name> <Name>XXXXXX XXXX</Name> <Name>XXXXXX XXX XXXXXX</Name> <Name> XXXXX </Name> to <Name> XXXXX </Name> 2. (see no space) <Name>XXX</Name> to <Name>XXX</Name> 3. <!--Name Jason /--> to <!--Name XXXXX /-->` 4. <!--Name Jas /--> to <!--Name XXX /--> starting tag, value and closing tag can all come in different line 5. <Name>XXX </Name> to <Name>XXX </Name> 6. <Name> XXX </Name> to <Name> XXX </Name> 7. <!--Name Jim /--> to <!--Name XXX /--> 8. <Name> XXXXX </Name> <Name> XXXXXXX </Name> to <Name> XXXXX </Name> <Name> XXXXXX </Name> 9. <Name> XXXXX XXXXXXX </Name> to <Name> XXXXX XXXXXXX </Name> or <Name> XXXXXXXXXXXXX </Name> $

script.sed

这是相当扭曲的,对它有礼貌。它查找/<Name>.*<\/Name>/{ : l1 s/\(<Name>[[:space:]]*\(X[X[[:space:]]*\)\{0,1\}\)[^X<[:space:]]\(.*[[:space:]]*<\/Name>\)/\1X\3/ t l1 } 后跟零个或多个空格。接下来可以是<Name>,这意味着出现0或者一次X后跟一系列X或空格。所有这些都在替换中被捕获为\(X[X[[:space:]]*\)\{0,1\}。然后,单个字符不是\1X或空格,后跟零个或多个任何字符,零个或多个空格,以及<。中间的单个字符由X替换。重复整个替换,直到通过标签</Name>和条件分支: l1没有更多匹配。所有这些只能在同时包含t l1<Name>的行中运行。

</Name>

data

输出

<Name> Jason </Name>
<Name>Jim</Name>
<Name> Jason Bourne </Name>
<Name> Elijah </Name> <Name> Dennis </Name>
<Name> Elijah Wood </Name> <Name> Dennis The Menace </Name>
<Name>Elijah Wood</Name> <Name>Dennis The Menace</Name>
<Name> Jason
</Name>
<Name>
Jim</Name>
<Name> Jason
Bourne </Name>
<Name> Elijah </Name> <Name> Dennis
</Name>
<Name> Elijah
Wood </Name> <Name> Dennis
The Menace </Name>
<Name>Elijah
Wood</Name> <Name>Dennis The
Menace</Name>

注意更换部分到最后。这条线将导致更多的麻烦。

我还没有弄清楚脚本如何处理各种分割线情况,除了它几乎肯定需要连接线,直到$ sed -f script.sed data <Name> XXXXX </Name> <Name>XXX</Name> <Name> XXXXX XXXXXX </Name> <Name> XXXXXX </Name> <Name> XXXXXX </Name> <Name> XXXXXX XXXX </Name> <Name> XXXXXX XXX XXXXXX </Name> <Name>XXXXXX XXXX</Name> <Name>XXXXXX XXX XXXXXX</Name> <Name> Jason </Name> <Name> Jim</Name> <Name> Jason Bourne </Name> <Name> XXXXXX </Name> <Name> Dennis </Name> <Name> Elijah Wood </Name> <Name> Dennis The Menace </Name> <Name>Elijah Wood</Name> <Name>Dennis The Menace</Name> $ 被捕获。然后它会处理与已经显示的处理密切相关的处理,但它需要允许匹配材料中的换行符。

答案 1 :(得分:1)

试试这个python脚本:

$ cat script.py
#!/usr/bin/python
import re
from bs4 import BeautifulSoup
soup = BeautifulSoup(open('allcases'), features="xml")
for tag in soup.findAll('Name'):
    for name in 'Jason Ignacio', 'Jason', 'Jim':
        tag.string =  re.sub(r'\b%s\b' % name, len(name)*'X', tag.string)
print(str(soup))

此代码与python2或python3兼容。

要使其正常工作,您可能需要安装BeautifulSoup模块。在类似debian的系统上:

apt-get install python-bs4

或者,对于python3:

apt-get install python3-bs4

实施例

让我们考虑一下这个输入文件:

$ cat cases
<page>
<p>Jason</p>
<Name> Jason </Name>
<p>Jason</p>
 <Name>Jim</Name>
<p>Jim</p>
<Name>Jim
</Name>
<Name>
     Jim
       </Name>
<Name> Jason </Name> <Name> Ignacio </Name>
<Name> Jason Ignacio </Name>
</page>

让我们运行我们的脚本并观察输出:

$ python script.py
<?xml version="1.0" encoding="utf-8"?>
<page>
<p>Jason</p>
<Name> XXXXX </Name>
<p>Jason</p>
<Name>XXX</Name>
<p>Jim</p>
<Name>XXX
</Name>
<Name>
     XXX
       </Name>
<Name> XXXXX </Name> <Name> Ignacio </Name>
<Name> XXXXXXXXXXXXX </Name>
</page>

请注意,<p>标记中的名称是单独的。该代码仅更改<Name>代码中的名称。

此外,根据设计,JimJasonJason Ignacio更改为X,但其他名称保持不变。即使伊格纳西奥,如果它没有相邻的杰森,也会被单独留下。