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

Regex 使用awk将特定子字符串与正则表达式匹配,regex,bash,gawk,Regex,Bash,Gawk,我正在处理一个特定的文件名,需要从中提取信息 文件名的结构类似于:“20100613_M4_28007834.005_F_RANDOMSTR.raw.gz” 使用RANDOMSTR时,一个最多22个字符的字符串,其中可能包含格式为“-W[0-9].[0-9]{2}.[0-9]{3}”的子字符串(或不包含)。此子字符串还具有以“-W”开头的独特功能 我需要提取的信息是RANDOMSTR的子字符串,没有这个可选的子字符串 我想在bash脚本中实现这一点,到目前为止,我发现最好的选择是将gawk与正则

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

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

使用RANDOMSTR时,一个最多22个字符的字符串,其中可能包含格式为“-W[0-9].[0-9]{2}.[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,([0-9]{8}){uM[0-9])\\\[0-9]{8}\\\.[0-9]{3}.[uU9]{3}.[W].-raw.gz],arr);print arr[5]}这里的困难似乎是在可选的
(-W.-
之前的
(.
占据了后面的文本。使用非贪婪匹配也没有帮助。不幸的是,我的regex-fu太弱了,无法应对这种情况

如果您不介意使用多通道解决方案,那么一种更简单的方法是首先通过删除尾部的
.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。

你需要能够使用look-arounds,我认为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

$pat=”(?无法使用不情愿的量词,但按顺序运行两个正则表达式即可:

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

sed-E-E's/^.{27}(.*).raw.gz$/\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
$ 

您提到子字符串具有模式
“-W[0-9].[0-9]{2}.[0-9]{3}”
,但是您的示例输入包含
…W0.40+045.raw.gz
。您需要兼顾这两种模式吗?我不包括“.raw.gz”作为子字符串的一部分。抱歉,我的意思是提请注意加号,它不会包含在您的模式中。这意味着该模式只匹配我不希望从RANDOMSTR中得到的部分,而不是整个字符串。(我无法编辑我以前的注释)嗯,我有点懒,只是放了一个“.”在加号的位置。它匹配字符串,所以对我来说没问题。但最后我并没有真正使用该模式,使用“(-W.*)”对我来说就足够了。子字符串的模式只是作为参考提供的,以防有用。这绝对是更强的正则表达式fu!+1btw,除非我将其更改为
pat=”(?@Shawn:
(.+?)
可能更好,但它对我有效,如图所示。我只是复制并粘贴了我答案中的行,然后再次测试它,它有效(无论哪种方式)。两种方式都有效!它对我也有效,但仅使用Shawn的变体。遗憾的是,我的grep fu没有我的awk fu那么强大。如果经过一些测试,我无法得到我需要的结果(不在本期讨论的范围内),我会回复你:
(.*)
在RHEL5框上运行时有效,但在RHEL4上给出了一个空结果。奇怪的是,grep的版本是相同的(2.5.1),但Bash的版本不同(3.2 vs 3.0)。我希望它是grep的版本,而不是Bash。
sed-E的s/(-W[0-9].[0-9]{2}.[0-9]{3]?\.raw\.gz$/;s/*.\/'
…您不需要多个管道。(对于所有Linux用户,使用
sed-r
而不是
sed-E
)是的,非常正确。sed-E将执行一系列命令。我应该重新编写一个脚本:)
$ 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
$ 
$ awk -F_ '{sub(/(-W[0-9.+]+)?\.raw\.gz$/,"",$NF); print $NF}'