【问题标题】:extract first instance per line (maybe grep?)每行提取第一个实例(也许是 grep?)
【发布时间】:2016-12-14 10:21:27
【问题描述】:

我想在 linux 中提取每行字符串的第一个实例。我目前正在尝试 grep 但它每行产生所有实例。下面我想要“tn =”之后的字符串(数字和字母)......但只有每行的第一组。实际字符可以是数字或字母的任意组合。在他们之后有一个空间。 tn=之前还有一个空格

给定以下文件:

hello my name is dog tn=12g3 fun 23k3 hello tn=1d3i9 cheese 234kd dks2 tn=6k4k ksk

1263 chairs are good tn=k38493kd cars run vroom it95958 tn=k22djd fair gold tn=293838 tounge

期望的输出:

12g3

k38493

【问题讨论】:

  • 您真的希望在第二行输出中从tn=k38493kd 末尾删除kd 吗?如果是这样,请澄清您的要求,如果不能解决您的预期输出。

标签: linux ubuntu awk sed grep


【解决方案1】:

如果你有 GNU grep,这是你可以做到的一种方法,它(大部分)支持带有 -P 的 Perl 兼容正则表达式。此外,非标准开关-o 用于仅打印与模式匹配的部分,而不是整行:

grep -Po '^.*?tn=\K\S+' file

该模式匹配行的开头^,后跟任何字符.*?,其中? 使匹配非贪婪。在tn= 的第一场比赛之后,\K“杀死”了前一部分,因此您只剩下您感兴趣的部分:一个或多个非空格字符\S+

Ed's answer 一样,您可能希望在tn 之前添加一个空格,以避免意外匹配footn=... 之类的内容。您可能还喜欢使用 \w 之类的东西来匹配“单词”字符(相当于 [[:alnum:]_])。

【讨论】:

  • 啊,太好了,我用grep -Po '(?<=tn=)\w' file 玩过,它有效,但所有匹配项都排成一行。我喜欢它的工作原理。
【解决方案2】:
$ awk 'match($0,/ tn=[[:alnum:]]+/) {print substr($0,RSTART+4,RLENGTH-4)}' file
12g3
k38493kd

【讨论】:

  • 嗯,但是如果行以tn=23 开头怎么办?正则表达式中的前导空格将使其不匹配。可能值得使用\< 并说awk 'match($0,/\<tn=[[:alnum:]]+/) {print substr($0,RSTART+3,RLENGTH-3)}' file
  • OP 说There is also a space before the tn=。使用 \< 会使它不必要地特定于 gawk。
【解决方案3】:

只需将输入拆分为tn=-separators 并选择第二个。然后,再次拆分以使所有内容都达到第一个空格:

$ awk -F"tn=" '{split($2,a, " "); print a[1]}' file
12g3
k38493kd

【讨论】:

  • 关于多字符 FS,任何符合 POSIX 的 awk 都应该支持它。与 RS 相关的 GNU 特定行为。
  • @TomFenech 哦,很高兴知道!我看到它在POSIX awk page 中有所描述。谢谢
  • 如果footn=27 出现在输入中的tn=35 之前,则会失败。
  • @EdMorton 没有footn=27 数据将只有foo tn=27,只有空格。
猜你喜欢
  • 1970-01-01
  • 2017-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-24
  • 2022-08-18
  • 2020-03-03
  • 1970-01-01
相关资源
最近更新 更多