bash - 更改文件中两个带有字符 X 的字符串之间的字符串

标签 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"

最佳答案

临时解决方案

这扩展了下面的“首次发行”并处理情况 1、2、5、6、8、9。它不处理有一个或多个完整 <Name>…</Name> 的情况。条目以及起始 <Name>没有匹配的</Name>在同一条线上。坦率地说,我什至不知道如何开始解决这种情况。

未处理的情况 3、4、7 不是有效的 XML — 我也不相信它们是有效的 HTML(或 XHTML)。我相信它们可以通过与此处显示的完整 <Name>…</Name> 类似(但更简单)的机制来处理。版本。我将其作为练习留给读者(注意字符类中的 < — 它需要变成 / )。

script.sed

/<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
}

第一行“跳过”不包含 <Name> 的行的处理(它们被打印并读取下一行)。接下来的 6 行是“首次发行”中的脚本,只不过有一个 b跳转到处理结束。

新部分是/<Name>/,/<\/Name>/代码。这寻找 <Name>本身,并连接最多 4 行,直到 </Name>包含在模式空间中。这两行注释用于调试——它们使我能够看到什么被视为一个单元。除非使用标签l2代替l1 ,其余部分与首次发行时完全相同 - sed正则表达式已经适应换行符。

这是重型 sed脚本而不是我想要使用或维护的内容。我会选择使用 XML 解析器的 Perl 解决方案(因为我比 Python 更了解 Perl),但使用适当的 XML 解析器,Python 也能很好地完成这项工作。

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>

没有声称data文件包含最少的案例集;这是重复的。它包含问题中的 Material ,但“非正统”XML 元素(例如 <Name Value />)除外。转换为 XML 注释 <!--Name Value /--> 。映射实际上并不重要;重要的是。开头部分不匹配<Name> (并且尾部与 </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> 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>
$

首次发行

部分答案 - 但它说明了您面临的问题。处理问题中的情况 1 和 2,加上多词变体,您可以使用脚本:

script.sed

/<Name>.*<\/Name>/{
: l1
s/\(<Name>[[:space:]]*\(X[X[[:space:]]*\)\{0,1\}\)[^X<[:space:]]\(.*[[:space:]]*<\/Name>\)/\1X\3/
t l1
}

老实说,这相当扭曲。它寻找 <Name>后跟零个或多个空格。后面可以是 \(X[X[[:space:]]*\)\{0,1\} ,这意味着 X 出现零次或一次,后跟一系列 X 或空格。所有这些都被捕获为 \1在替换中。然后有一个字符不是 X , <或空格,后跟零个或多个任意字符、零个或多个空格以及 </Name> 。中间的单个字符被 X 替换。重复整个替换,直到通过标签 : 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>
$

注意最后的替换部分。这条线将会引起其他任何事情的头痛。

我还没有弄清楚脚本如何处理各种分行情况,除此之外几乎肯定需要连接行,直到 </Name>被捕获了。然后,它将执行与已显示的内容密切相关的处理,但需要允许匹配 Material 中的换行符。

关于bash - 更改文件中两个带有字符 X 的字符串之间的字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38911200/

相关文章:

bash - 检查 iptables 用户链是否存在的最佳方法

linux - 如何解析我想在 shell 命令中提取的单词?

linux - 用sed分隔一个文本文件

linux - Sed 不能正常工作

python - 如何删除大型法语文本文件中的所有特殊字符

linux - shell中两个日期之间的天数差异

linux - 我们如何找到位于目录树中某个位置的文件

linux - 使用 for 循环将变量连接成以逗号分隔的单个变量

linux - 如何在使用 linux shell 时过滤多个文件并消除重复条目以选择单个条目

awk:对最后一个单词的文本 block 进行分组在两个文本文件中都很常见