假设我有一行文本行,其中一个数字位于某处(可能位于行的开头,中间或末尾)。
如何使用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
......
答案 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
它打印文件中的所有数字,并在打印时用空格分隔捕获的数字。