假设我有这样的行:
*[234]*
*[23]*
*[1453]*
其中*
表示任何字符串(除了 形式的字符串[number]
)。如何使用命令行实用程序解析这些行并提取括号之间的数字?
更一般地说,这些工具cut
、sed
、grep
或中的哪一个awk
适合此类任务?
答案1
如果您有 GNU grep,则可以使用其-o
选项来搜索正则表达式并仅输出匹配的部分。 (其他 grep 实现只能显示整行。)如果一行上有多个匹配项,它们将打印在单独的行上。
grep -o '\[[0-9]*\]'
如果你只想要数字而不想要括号,那就有点困难了;您需要使用零宽度断言:与空字符串匹配的正则表达式,但前提是它前面或后面有括号(视情况而定)。零宽度断言仅在 Perl 语法中可用。
grep -P -o '(?<=\[)[0-9]*(?=\])'
使用 sed,您需要使用 关闭打印-n
,并匹配整行并仅保留匹配的部分。如果一行中有多个可能的匹配项,则仅打印最后一个匹配项。看提取与“sed”匹配的正则表达式而不打印周围的字符有关使用 sed 的更多详细信息,请参见此处。
sed -n 's/^.*\(\[[0-9]*\]\).*/\1/p'
或者如果您只想要数字而不是括号:
sed -n 's/^.*\[\([0-9]*\)\].*/\1/p'
如果没有grep -o
,如果您想要既简单又易于理解的东西,Perl 是您的首选工具。在每一行 ( -n
) 上,如果该行包含 的匹配项\[[0-9]*\]
,则打印该匹配项 ( $&
) 和换行符 ( -l
)。
perl -l -ne '/\[[0-9]*\]/ and print $&'
如果您只需要数字,请在正则表达式中放入括号来分隔组,然后仅打印该组。
perl -l -ne '/\[([0-9]*)\]/ and print $1'
PS 如果您只想要求括号之间包含一位或多位数字,请在 Perl 中更改为[0-9]*
,[0-9][0-9]*
或 to [0-9]+
。
答案2
你不能用 来做到这一点cut
。
tr -c -d '0123456789\012'
sed 's/[^0-9]*//g'
awk -F'[^0-9]+' '{ print $1$2$3 }'
grep -o -E '[0-9]+'
tr
是最适合该问题的,并且可能运行速度最快,但我认为您需要大量输入才能在速度方面分离这些选项中的任何一个。
答案3
如果您的意思是在非数字字符之间提取一组连续数字,我想sed
和awk
是最好的(尽管grep
也能够为您提供匹配的字符):
sed
:您当然可以匹配数字,但做相反的事情也许很有趣,删除非数字(只要每行只有一个数字):
$ echo nn3334nn | sed -e 's/[^[[:digit:]]]*//g'
3344
grep
:可以匹配连续的数字
$ echo nn3334nn | grep -o '[[:digit:]]*'
3344
我没有给出例子,awk
因为我对此没有任何经验;有趣的是,虽然sed
它是一把瑞士刀,grep
但它为您提供了一种更简单、更易读的方法来执行此操作,它也适用于每个输入行上的多个数字(-o
唯一打印输入的匹配部分,每个在自己的线路上):
$ echo dna42dna54dna | grep -o '[[:digit:]]*'
42
54
答案4
既然有人说这不能用 来完成cut
,我将证明可以很容易地产生一个至少不比其他一些解决方案差的解决方案,即使我不赞成使用 为cut
“最佳” (甚至是一个特别好的)解决方案。应该说,任何不专门寻找数字*[
及其]*
周围数字的解决方案都会做出简化的假设,因此在比提问者给出的更复杂的示例上很容易失败(例如,*[
和之外的数字]*
,不应显示)。该解决方案至少检查括号,并且还可以扩展以检查星号(留给读者作为练习):
cut -f 2 -d '[' myfile.txt | cut -f 1 -d ']'
这利用了-d
指定分隔符的选项。显然,您也可以通过管道输入cut
表达式,而不是从文件中读取。虽然cut
可能相当快,因为它很简单(没有正则表达式引擎),所以您必须调用它至少两次(或者更多时间来检查*
),这会产生一些进程开销。该解决方案的一个真正优点是它具有相当的可读性,特别是对于不熟悉正则表达式构造的临时用户。