我有一系列的线条形式。
Agenda HR-1 Presented by XYZ
HR-2 Debate-1 - All
HR-3 Debate-2 - All
(Cov-4) Conclusion
每一行都有一个 (sed) 模式的 ID [A-Za-z]\+-[0-9]\+
,即一个或多个字母后跟一个破折号 (-),后跟一个或多个数字。它们出现在队列中的任何位置。
我需要提取 ID。我的想法是.*
在开头和结尾粘贴 a并打印\1
,但我无法让它工作。
这回复说 sed 仅替换第一个匹配项,这是正确的:
$ cat /tmp/scratch/x | sed -n 's/\<\([A-Za-z]\+-[0-9]\+\)/ID:\1/p'
Agenda ID:HR-1 Presented by XYZ
ID:HR-2 Debate-1 - All
ID:HR-3 Debate-2 - All
(ID:Cov-4) Conclusion
但当然,.*
开始时会贪婪地转到最后一场比赛:
$ cat /tmp/scratch/x | sed -n 's/.*\<\([A-Za-z]\+-[0-9]\+\).*/ID:\1/p'
ID:HR-1
ID:Debate-1
ID:Debate-2
ID:Cov-4
我能想到的唯一方法sed
是在一个命令中的 ID 周围添加标记,然后使用另一个命令进行提取,如下所示。
在 sed 中是否有更好的方法来做到这一点?
$ cat x | sed -n 's/\<\([A-Za-z]\+-[0-9]\+\)/<id>\1<~id>/;s/.*<id>\(.*\)<~id>.*/\1/;p'
HR-1
HR-2
HR-3
Cov-4
答案1
使用 GNU awk
,尝试:
gawk -v FPAT='[A-Za-z]+-[0-9]+' '$1{print $1}' FILE
或者:
gawk -v FPAT='[A-Za-z]+-[0-9]+' '$0=$1' FILE
答案2
与sed
,尝试:
<FILE sed -En '/([[:alpha:]]+-[0-9]+).*/{ s//:\1/; s/.*://p; }'
- 删除所需匹配项后的所有内容
- 现在匹配位于每一行的末尾——这可以通过多种方式处理
- 上面的内容很容易阅读 -
char
在每场比赛之前放置不属于比赛一部分的 a ,然后char
使用第二个s
命令删除直到最后一个的所有内容 - 第二个
s
命令的另一个选项是删除不属于匹配部分的字符之前的所有内容:
- 上面的内容很容易阅读 -
<FILE sed -En '/([[:alpha:]]+-[0-9]+).*/{ s//\1/; s/.*[^[:alnum:]-]//; p; }'
答案3
我们Perl
可以这样做:
$ perl -lne 'print /([a-z]+-\d+)/i' file
输出:
HR-1
HR-2
HR-3
Cov-4