grep 字符串中路径、制表符和空格后面的数字

grep 字符串中路径、制表符和空格后面的数字

给定一个字符串 s

s="B /home/BL/004_010_0100.0      23      0.031"

如何只 grep 字符串中路径、制表符和空格后面的数字?

在上面的字符串 s 中,我想提取数字 23。

num=$(echo $s | grep 'B .*\t (\d*)')

答案1

将字符串视为一组空格分隔的字段,您需要倒数第二个字段:

num=$( awk '{ print $(NF-1) }' <<<"$s" )

或者,在没有此处字符串的 shell 中,

num=$( printf '%s\n' "$s" | awk '{ print $(NF-1) }' )

这会将字符串输入$sawk命令中。该awk命令输出倒数第二个以空格分隔的字段。该结果被分配给num变量。

测试:

$ s="B /home/BL/004_010_0100.0      23      0.031"
$ num=$( awk '{ print $(NF-1) }' <<<"$s" )
$ printf 'num is "%s"\n' "$num"
num is "23"

如果您的数据来自$s命令,那么您可以awk直接将其输入,而不是将其存储在中间变量中:

num=$( some-command | awk '{ print $(NF-1) }' )

grep是一个返回匹配的工具线-o(忽略该工具的某些实现中可用的非标准选项)。如果我们首先根据字符串中的空格将字符串转换为多行,我们可以用来grep挑选数字:$s

$ tr -s '[:blank:]' '[\n*]' <<<"$s" | grep -x '[[:digit:]]\{1,\}'
23

这里使用的命令tr将字符串从

B /home/BL/004_010_0100.0      23      0.031

进入

B
/home/BL/004_010_0100.0
23
0.031

grep命令选出了这一行仅有的由数字组成(该-x选项将强制给定的模式匹配完整的行)。显然,只有当您要查找的数字是正整数时,这才有效。

如果您知道您会对倒数第二个“字段”感兴趣,那么您可以使用tailandhead代替:

$ tr -s '[:blank:]' '[\n*]' <<<"$s" | tail -n 2 | head -n 1
23

... 或者sed

$ tr -s '[:blank:]' '[\n*]' <<<"$s" | sed -n -e '${ g; p; }' -e h
23

上述所有变体都是标准且便携式的。cut如果我们使用非标准rev实用程序反转该行两次,我们还可以用来提取倒数第​​二个字段:

$ rev <<<"$s" | tr -s '[:blank:]' '[\t*]' | cut -f 2 | rev
23

在这里,我们还聘请tr制表符替换所有空白字符(并将它们压缩到单身的选项卡)。 cut然后简单地提取第二个字段,然后rev再次反转提取的数据。

答案2

你可以用 Perl 尝试一下:

echo "$s" | perl -e 'for(<>){/B\s+.*?\s+(\d+)\s+/;print $1}'

在这里我们找到带有以下内容的字符串:

  • B特点
  • 后跟一个或多个空格字符 -\s+
  • 后跟第一个空格字符之前的所有惰性字符 -.*?\s+
  • 接下来是我们想要的数字 - 将其捕获在括号中的捕获组中(\d+)- 它保存在$1特殊变量中
  • 后跟一个或多个空格字符 - \s+

这个正则表达式可以被改进(例如使用^$运算符来指出字符串的开头和结尾)。

阅读更多关于正则表达式。

答案3

如果您有权访问 GNU grep(Linux 系统上的默认设置),则此正则表达式将捕获不带任何小数的数字。

grep -oP '\b(?<!\.)\d+(?!\.)\b'

正则表达式解释:

  • \b匹配单词边界
  • (?<!\.)负向后查找断言后面没有小数点(.
  • \d+匹配一个数字一次或多次
  • (?!\.)负向先行断言前面没有小数点( .)
  • \b匹配单词边界

答案4

只是改变了grep一点。如果您使用 GNU grep(Linux 系统上的默认设置),这应该可以工作:

s="B /home/BL/004_010_0100.0      23      0.031"
num=$(echo $s | grep -oP '\.*?\s+\d+\s+')

相关内容