使用sed匹配第5个字段中的文本

时间:2016-05-08 20:03:47

标签: linux bash unix sed

所以,我试图在/ etc / passwd的第5个字段中查找某些单词。 例如:

jonesc:x:1053:1001:Cathy Jones:/export/home/jonesc:/bin/ksh
smiths:x:1049:1000:Sue Williams:/export/home/smiths:/bin/csh
smitha:x:1050:1001:Amy Smith:/export/home/smitha:/bin/bash

让我们说我正在寻找'史密斯'这个词?我如何才能在包含名称的第5个字段中查找它,而不是查看整行?

我可以使用awk轻松完成此操作,但我要求用sed执行此操作。

我要求做的是将第5个字段中包含Smith或Jones的/ etc / passwd中的匹配输出到名为smith_jones.txt的文件中。

我用sed将输出写入文件没有问题,我只是坚持我应该只在第5场中查找。 Awk将使用5美元,但我找不到与sed类似的东西。

没有找到完整的答案交给我,而是朝着正确的方向努力。

3 个答案:

答案 0 :(得分:5)

Awk将是这项工作的正确工具:

awk '$5 ~ /smith|jones/{print}' /etc/passwd > output.txt

但是既然你要求sed解决方案,那么你可以使用这样的东西:

sed -n '/[^:]*:[^:]*:[^:]*:[^:]*:\(smith\|jones\)/p' /etc/passwd

每个[^:]*除了:以外的所有内容都会匹配零次或多次。

您还可以使用范围元序列重复以前的模式:\{x,y\}

sed -n '/\([^:]*:\)\{4\}\(smith\|jones\)/p' /etc/passwd

正如您所看到的,这将有助于您进一步简化正则表达式。

-n默认情况下不打印,/pattern/p会打印与pattern匹配的所有内容

如果您想匹配用户名的中间位置,可能需要在[^:]*之前添加另一个\(smith\|jones\),例如:

sed -n '/\([^:]*:\)\{4\}[^:]*\(th\|es\)/p' /etc/passwd

将匹配SmithJones

正如评论中所指出的,您还可以使用扩展正则表达式来避免所有这些反斜杠:

sed -E -n '/([^:]*:){4}(smith|jones)/p' /etc/passwd

传统上GNU sed使用-r启用ERE,BSD sed使用-E。但GNU sed支持-E标志,即使它没有文档。

答案 1 :(得分:0)

这应该有效:

sed -n '/^\([^:]*:\)\{4\}[^:]*\(Jones\|Smith\)/p' /etc/passwd

^\([^:]*:\)\{4\}匹配以:分隔的前四个字段,因此第五个字段与名称(琼斯和史密斯)匹配。

答案 2 :(得分:0)

尝试一下:

sed -n ":1
/^[^:]*:[^:]*:[^:]*:[^:]*:[^:]*Smith[^:]*:.*$/ {p
n
b1}
/^[^:]*:[^:]*:[^:]*:[^:]*:[^:]*Jones[^:]*:.*$/{p}"

-n指示sed不打印任何内容

:1定义标签

/^[^:]*:[^:]*:[^:]*:[^:]*:[^:]*Smith[^:]*:.*$/正则表达式匹配第5个字段中包含Smith的任何字符串,其中字段以:分隔。

p是打印当前行的命令。

n是一个将下一行加载到缓冲区的命令。

b1转到标签1

sed一次读取一行文件。当前行存储在缓冲区中。如果在第5个字段中找到Smith,则打印该行,并将下一行存储到缓冲区中,然后转到标签1.否则,如果在第5个字段中找到Jones,则在打印缓冲区。

测试:

$ sed -n ":1
/^[^:]*:[^:]*:[^:]*:[^:]*:[^:]*Smith[^:]*:.*$/ {p
n
b1}
/^[^:]*:[^:]*:[^:]*:[^:]*:[^:]*Jones[^:]*:.*$/{p}" /etc/passwd >> smith_jones.txt

$ cat smith_jones.txt
jonesc:x:1053:1001:Cathy Jones:/export/home/jonesc:/bin/ksh
smitha:x:1050:1001:Amy Smith:/export/home/smitha:/bin/bash