sed返回的比我需要的多

时间:2016-02-24 12:57:22

标签: regex sed

输入文件的每一行都将匹配其中一种模式:

"SCnnnn"
"SC-nnnn"
"SC_nnnn"

(n = [0-9],SC是文字的,但可以是大写或小写,最后会有1-4个数字,最后用字母数字,空格或其他非数字字符分隔)

该行的某处还会有一个文件扩展名(匹配“.abc”),其中abc = upper | lower字母数字在任何位置。

我想提取第一个模式并将其与每行的解压缩文件扩展名一起打印。这就是我到目前为止所做的:

sed -E -n 's/([Ss][Cc][-_]*[0-9][0-9]*).*(\.[a-zA-Z0-9]{3})/\1\2/p' infile

这是一个示例输入行:

SCSCSCSCSCSCSCSCSC1867SCBrSCSCSCSC&SCBlSCkSCSCBSCrSCbSCckSC.xyz

所需的输出为:

SC1867.xyz

但我得到的是:

SCSCSCSCSCSCSCSCSC1867.xyz

有人可以告诉我为什么这会在我想要的部分之前返回“SC”吗?我知道这与贪婪有关,但我无法理解它。

(一切正常,我的“SCnnn”匹配位于该行的开头。)

我对其他工具持开放态度 - 例如awk - 如果他们提供更直接的解决方案。

编辑:我认为我找到了一个解决方案 - 至少看起来有效:

sed -E -n 's/.*([Ss][Cc][-_]*[0-9][0-9]*).*(\.[a-zA-Z0-9]{3})/\1\2/p'

1 个答案:

答案 0 :(得分:0)

这实际上不一定是在这里发挥作用的贪婪。发生这种情况的原因是因为sed正在替换一行的一部分,然后打印整行(p命令的后缀s//执行此操作)。

为了更清楚地了解发生了什么,make infile包含一个更明显的字符串,如0o0o0o0o0o0o0o0oSC1867lalalalalalfalalala.xyz并运行您的第一个命令。以下是结果

[user@localhost ~]$ sed -E -n 's/([Ss][Cc][-_]*[0-9][0-9]*).*(\.[a-zA-Z0-9]{3})/\1\2/p' infile
0o0o0o0o0o0o0o0oSC1867.xyz

作为一个慢动作:sed在0o0o0之后找到你的[Ss] [Cc]字符,并尽职尽责地用你想要的替换代替你描述的字符串;即,它保持SC_ - 类似的部分和四位数,然后删除数字后的所有内容,直到后缀。当p命令打印出部分更改的行时,会出现此问题,包括所有不需要的 0o ze。

替代地

作为替代解决方案,不涉及打印部分更改的行,而是匹配整行并将其更改为您的目的,以下命令为包含示例字符串的文件提取了stdout的正确答案:

[user@localhost ~]$ sed -e 's/^.*\([Ss][Cc][-_]\?[0-9]\{4\}\).*\(\.[a-Z]\{3\}\)$/\1\2/' infile
SC1867.xyz

将该正则表达式向下打破:正则表达式从行的开头(^)开始,消耗所有字符(.*),直到它看到SC(上部或下部,{{1然后它检查一个可选的连字符或下划线([Ss][Cc]),后面跟着正好四位数([-_]\?)。然后,所有字符都被消耗,直到看到一个点([0-9]\{4\}),然后是正好三个字母数字字符(\.)和一个行尾([a-Z]\{3\})。通配符未使用的两个表达式将保存到寄存器并连接($)。

... \1\2也适用,如果你不像我一样喜欢反斜杠。