使用awk将特定子字符串与正则表达式匹配

时间:2010-12-15 12:49:25

标签: regex bash gawk

我正在处理特定的文件名,需要从中提取信息。

文件名的结构类似于:“20100613_M4_28007834.005_F_RANDOMSTR.raw.gz”

使用RANDOMSTR一串最多22个字符,并且可以包含格式为“-W [0-9]。[0-9] {2}。[0-9] {0}的子字符串(或不包含)。[0-9] {3 }”。此子字符串还具有以“-W”开头的独特功能。

我需要提取的信息是没有这个可选子字符串的RANDOMSTR的子字符串。

我想在bash脚本中实现它,到目前为止,我找到的最佳选择是使用带有正则表达式的gawk。到目前为止,我最好的尝试失败了:

gawk --re-interval '{match ($0,"([0-9]{8})_(M[0-9])_([0-9]{8}\\.[0-9]{3})_(.)_(.*)(-W.*)?.raw.gz",arr); print arr[5]}' <<< "20100613_M4_28007834.005_F_OTHER-STRING-W0.40+045.raw.gz"
OTHER-STRING-W0.40+045

预期结果如下:

gawk --re-interval '{match ($0,$regexp,arr); print arr[5]}' <<< "20100613_M4_28007834.005_F_SOME-STRING.raw.gz"
SOME-STRING
gawk --re-interval '{match ($0,$regexp,arr); print arr[5]}' <<< "20100613_M4_28007834.005_F_OTHER-STRING-W0.40+045.raw.gz"
OTHER-STRING

如何才能获得理想的效果。

感谢。

4 个答案:

答案 0 :(得分:2)

你需要能够使用环顾四周,我不认为awk / gawk支持,但是grep -P会这样做。

$ pat='(?<=[0-9]{8}_M[0-9]_[0-9]{8}\.[0-9]{3}_._)(.*?)(?=(-W.*)?\.raw\.gz)'
$ echo "20100613_M4_28007834.005_F_SOME-STRING.raw.gz" | grep -Po "$pat"
SOME-STRING
$ echo "20100613_M4_28007834.005_F_OTHER-STRING-W0.40+045.raw.gz" | grep -Po "$pat"
OTHER-STRING

答案 1 :(得分:1)

虽然grep解决方案确实非常好,但OP没有提到操作系统,-P选项似乎只在Linux中可用。在awk中执行此操作也非常简单。

$ awk -F_ '{sub(/(-W[0-9].[0-9]+.[0-9]+)?\.raw\.gz$/,"",$NF); print $NF}' <<EOT
> 20100613_M4_28007834.005_F_SOME-STRING.raw.gz
> 20100613_M4_28007834.005_F_OTHER-STRING-W0.40+045.raw.gz
> EOT
SOME-STRING
OTHER-STRING
$ 

请注意,这会打破&#34; 20100613_M4_28007834.005_F_OTHER-STRING-W0_40 + 045.raw.gz&#34;。如果这是一个风险,并且-W仅显示在上面显示的位置,那么最好使用以下内容:

$ awk -F_ '{sub(/(-W[0-9.+]+)?\.raw\.gz$/,"",$NF); print $NF}'

答案 2 :(得分:0)

这里的困难似乎是可选(.*)之前的(-W.*)?吞噬后一文本。使用非贪婪的匹配也无济于事。不幸的是,我的正则表达式太弱了,不能解决这个问题。

如果您不介意多次通过解决方案,那么更简单的方法是首先通过删除尾随的.raw.gz和可能的-W*来清理输入。

str="20100613_M4_28007834.005_F_OTHER-STRING-W0.40+045.raw.gz"
echo ${str%.raw.gz}  | # remove trailing .raw.gz
     sed 's/-W.*$//' | # remove trainling -W.*, if any
     sed -nr 's/[0-9]{8}_M[0-9]_[0-9]{8}\.[0-9]{3}_._(.*)/\1/p'

我使用了sed,但你也可以使用gawk / awk。

答案 3 :(得分:0)

无法让不情愿的量词进行,但按顺序运行两个正则表达式可以完成这项工作:

sed -E -e 's/^.{27}(.*).raw.gz$/\1/' << FOO | sed -E -e 's/-W[0-9.]+\+[0-9.]+$//'
20100613_M4_28007834.005_F_SOME-STRING.raw.gz
20100613_M4_28007834.005_F_OTHER-STRING-W0.40+045.raw.gz
FOO