如何使用sed匹配并保持第一个数字在一行?

时间:2014-06-02 16:43:40

标签: regex sed

问题

假设我有一行文本行,其中一个数字位于某处(可能位于行的开头,中间或末尾)。

如何使用sed匹配并保留在一行中找到的第一个号码?

最小的例子

这是我的尝试(关于正则表达式的教程的this page之后)以及该数字的不同位置的输出:

$echo "SomeText 123SomeText" | sed 's:.*\([0-9][0-9]*\).*:\1:'
3
$echo "123SomeText" | sed 's:.*\([0-9][0-9]*\).*:\1:'
3
$echo "SomeText 123" | sed 's:.*\([0-9][0-9]*\).*:\1:'
3

因为你只能在过程中保留最后一位数字,而所需的输出应该是123 ......

4 个答案:

答案 0 :(得分:3)

使用sed:

echo "SomeText 123SomeText 456" | sed -r 's/^[^0-9]*([0-9]+).*$/\1/'
123

您也可以在gnu awk中执行此操作:

echo "SomeText 123SomeText 456" | awk '{print gensub(/^[^0-9]*([0-9]+).*$/, "\\1", $0)}'
123

答案 1 :(得分:3)

您还可以使用grep,它非常适合此任务。 sed是一个Stream EDitor,它只是间接地给你你想要的东西。使用grep,您只需指定所需行的部分。

$ cat file.txt
SomeText 123SomeText
123SomeText
SomeText 123
$ grep -o '[0-9]\+' file.txt
123
123
123

grep -o仅打印一行的匹配部分,每个部分都在一个单独的行上。模式很简单:一个或多个数字。

如果您的grep版本与-P开关兼容,则可以使用Perl样式的正则表达式并使命令更短:

$ grep -Po '\d+' file.txt
123
123
123

再次,这匹配一个或多个数字。

使用grep要简单得多,并且如果行不匹配则不会打印任何内容:

$ echo "no number" | grep -Po '\d+'     # no output
$ echo "yes 123number" | grep -Po '\d+'
123

修改

正如评论中所指出的,一个可能的问题是,这不仅会打印该行上的第一个匹配数字。如果该行包含多个数字,则将全部打印。据我所知,使用grep -o无法做到这一点。

在那种情况下,我会选择perl:

perl -lne 'print $1 if /.*?(\d+).*/'

这使用延迟匹配(问号),因此在模式开始时.*仅消耗非数字字符。 $1是后向参考,例如sed中的\1。如果该行上有多个号码,则仅打印第一个号码。如果根本没有,它不会打印任何内容:

$ echo "no number" | perl -ne 'print "$1\n" if /.*?(\d+).*/'
$ echo "yes123number456" | perl -lne 'print $1 if /.*?(\d+).*/'
123

如果由于某种原因你仍然真的想使用sed,你可以这样做:

sed -n 's/^[^0-9]*\([0-9]\{1,\}\).*$/\1/p'

与其他答案不同,它与所有版本的sed兼容,只会打印包含匹配项的行。

答案 2 :(得分:3)

为了补充sed解决方案,这里有 awk替代(假设目标是在每行提取 1st 号码,如果有的话(即忽略没有任何数字的行)):

awk -F'[^0-9]*' '/[0-9]/ { print ($1 != "" ? $1 : $2) }'
  • -F'[^0-9]*'定义任何非数字字符序列。 (包括空字符串)作为字段分隔符; awk会根据该分隔符自动将每个输入行分为多个字段,$1代表第一个字段,$2代表第二个字段,依此类推。
  • /[0-9]/是一种模式(条件),它确保仅通过其关联的操作({...}块)为包含至少一个数字的行生成输出 - 换句话说:包含的行根本没有数字会被忽略。
  • { print ($1!="" ? $1 : $2) }打印第一个字段,如果非空,则打印第二个字段;理由:如果行开头, 1st 字段将包含该行的第一个数字(因为该行以字段开头)而不是分隔符;否则, 2nd 字段包含第一个数字(因为该行以分隔符开头)。

答案 3 :(得分:1)

试试这个sed命令,

$echo "SomeText 123SomeText" | sed -r '/[^0-9]*([0-9][0-9]*)[^0-9]*/ s//\1 /g'
123

另一个例子,

$ echo "SomeText 123SomeText 456" | sed -r '/[^0-9]*([0-9][0-9]*)[^0-9]*/ s//\1 /g'
123 456

它打印文件中的所有数字,并在打印时用空格分隔捕获的数字。