在sed的正则表达式中包含可选字符

时间:2019-04-14 11:02:38

标签: sed

我有以下字符串:

setenv run_area1 root/test1/Apr14_2019_10_32_39/dummy
setenv area2 root/test2/Aug23_2017_14_25_56/dummy
setenv run_area3 testRun/test1/blue_Apr14_2019_08_56_48/dummy/
setenv area4 testRun/test2/Aug23_2017_14_26_03/thing2

我要用[DATE]替换日期,如下所示:

setenv run_area1 root/test1/[DATE]/dummy
setenv area2 root/test2/[DATE]/dummy
setenv run_area3 testRun/test1/blue[DATE]/dummy/
setenv area4 testRun/test2/[DATE]/thing2

我必须使用sed,所以我写了以下命令:

sed 's|[A-Z][a-z]*[0-9]*_[0-9]*_[0-9]*_[0-9]*_[0-9]*|[DATE]|g'

它对于字符串很有效,但对于以下字符串却有效:

setenv run_area3 testRun/test1/blue_Apr14_2019_08_56_48/dummy/

我得到:

setenv run_area3 testRun/test1/blue_[DATE]/dummy/

我正在寻找一种在正则表达式中使用_的方法。在perl中,我知道我可以使用类似(_|)的东西,因此_是可选的。我也可以使用?。 对于以前的线程,我看到基本的sed不包括那些选项,我需要使用\{0,1\}。 (link)。 问题是,我似乎无法理解\{0,1\}是如何解决它的。还有其他解决方案吗?

3 个答案:

答案 0 :(得分:1)

BRE中的

\{0,1\}是一个正则表达式间隔,表示0 to 1 repetitions of the preceding expression与ERE中的?相同(在ERE中,其定义为0 _or_ 1,但这是一组相同的值!),即前面的表达式是可选的。

使用任何POSIX sed:

$ sed 's/_\{0,1\}[[:upper:]][[:lower:]]*[0-9]*\(_[0-9]*\)\{4\}/[DATE]/' file
setenv run_area1 root/test1/[DATE]/dummy
setenv area2 root/test2/[DATE]/dummy
setenv run_area3 testRun/test1/blue[DATE]/dummy/
setenv area4 testRun/test2/[DATE]/thing2

答案 1 :(得分:0)

因为sed使用defaultbasic regular expression。有关basic regular expressionextended regular expression之间的区别,请参阅此link

如果要使用extended regular expression支持的功能。您必须使用-r选项明确地告诉sed。

因此,使用 GNU sed ,下面的脚本实际上会执行相同的操作。

sed 's|_\?[A-Z][a-z]*[0-9]*_[0-9]*_[0-9]*_[0-9]*_[0-9]*|[DATE]|g' textfile

sed -r 's|_?[A-Z][a-z]*[0-9]*_[0-9]*_[0-9]*_[0-9]*_[0-9]*|[DATE]|g' textfile

答案 2 :(得分:0)

如果月份和数据遵循MMMDD格式,则可以认为该表达式在记录中是唯一的,并基于此假设来创建整个脚本。如下所示:

sed -E 's/^(.*)([[:alpha:]]{3}[[:digit:]]{2})([^/]+)\/(.*)$/\1[DATE]\/\4/;s/_\[DATE\]/[DATE]/' filename

输出

setenv run_area1 root/test1/[DATE]/dummy
setenv area2 root/test2/[DATE]/dummy
setenv run_area3 testRun/test1/blue[DATE]/dummy/
setenv area4 testRun/test2/[DATE]/thing2

注意:带有-E的{​​{1}}选项启用扩展的正则表达式,如果不支持,则使用sed选项。