如何在 sed 中仅打印出现的模式?

如何在 sed 中仅打印出现的模式?

我的 Linux 机器上有一些用分号分隔的数据。我需要找到第 N 个(例如 3d)单词并打印它而不是整行。我有以下脚本,可以找到所需的模式并将其放在 之间_,这样我就可以看到它正常工作:

sed 's/\;[^;]*\;/_&_/3'

例如对于此输入:

A1a 77l;a3sSs 2 smm;AS 3N123N8j a5njs;M3Xa 4 4a 3n1J  S2a;sm i;A9S;dd d3

它输出:

A1a 77l;a3sSs 2 smm;AS 3N123N8j a5njs;M3Xa 4 4a 3n1J  S2a;sm i_;A9S;_dd d3

现在,当我已经找到模式时,我想简单地打印它而不是整行,以便输出为:

A9S

答案1

sed -E 's/(([^;]*);){6}.*/\2/'

会做到的,其中6是您要捕获的字段编号。

(如果您指定的字段编号大于输入中的字段数量,则它只会回显输入而不进行任何替换。)

我使用了该-E选项,它启用了扩展正则表达式。根据您拥有的 sed 版本,您可能需要使用-r它。或者,跳过该选项,以便使用基本正则表达式,并转义括号和花括号:

sed 's/\(\([^;]*\);\)\{6\}.*/\2/'

怎么运行的:

sed 将在最早的可能位置找到匹配项,在本例中,从第一个字符开始有一个匹配项(假设您的输入中至少有 6 个字段)。外括号表达式与后跟分隔符的字段匹配;。该命令将6连续匹配这些(或您指定的任何数字)。末尾.*的 与该行的其余部分匹配。结果,整条生产线都被更换。

它会被什么取代?\2指内括号表达式(以第二个左括号开头的表达式)。该内部括号表达式实际上匹配了 6 次,但 sed 将使用最后一次匹配,这正是您想要的。

具有更好功能的版本:

如果指示的字段不存在(在示例中,如果输入中的字段少于 6 个),此版本将用空字符串替换整行:

sed -E 's/(([^;]*);){6}.*/\2/;t;d'

在 OS X 的 sed 版本上(也许还有 BSD?),这似乎需要写成两行:

sed -E 's/(([^;]*);){6}.*/\2/;t
d'

t如果进行了替换,该命令将终止 sed 对此输入行的处理。

因此,如果第 6 个字段存在,则像以前一样进行替换,并且t命令结束对此输入行的处理。但如果第 6 个字段不存在,则该s命令不会进行替换,因此t不会分支; sed 只是继续执行该d命令,该命令删除输入行(如果输入行中的字段少于 6 个,这就是我们想要做的)。

答案2

;要从文件中获取第三个分隔字段,请使用cut

$ cut -d ';' -f 3 file
AS 3N123N8j a5njs

要获取您显示的字段,请剪切第 6 个字段:

$ cut -d ';' -f 6 file
A9S

您也可以使用awk来执行此操作awk -F ';' '{ print $6 }' file

对于sed,您不能使用命令/n的标志s(作为n数字),因为您需要替换全线。这实际上涉及到匹配整个生产线,而不仅仅是某个特定领域。

因此,获得第六个;分隔字段的一种方法是使用

$ sed 's/^\([^;]*;\)\{5\}\([^;]*\);.*/\2/' file
A9S

或者,如果您sed支持扩展正则表达式-E

$ sed -E 's/^([^;]*;){5}([^;]*);.*/\2/' file
A9S

也就是说,匹配五个字段,其中每个字段都匹配[^;]+;(包括每个字段的终止;),然后是我们后面的字段,然后是该行的其余部分。用我们想要的字段替换所有这些。

简而言之,您最好使用cutawk来完成此任务。

相关内容