我的 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
也就是说,匹配五个字段,其中每个字段都匹配[^;]+;
(包括每个字段的终止;
),然后是我们后面的字段,然后是该行的其余部分。用我们想要的字段替换所有这些。
简而言之,您最好使用cut
或awk
来完成此任务。