用grep在一行中捕获正则表达式

时间:2017-07-11 21:19:21

标签: regex bash grep

在bash中,我的计算机上sensors的输出如下:

Adapter: ISA adapter
Physical id 0:  +67.0°C  (high = +84.0°C, crit = +100.0°C)
Core 0:         +65.0°C  (high = +84.0°C, crit = +100.0°C)
Core 1:         +65.0°C  (high = +84.0°C, crit = +100.0°C)
Core 2:         +65.0°C  (high = +84.0°C, crit = +100.0°C)
Core 3:         +67.0°C  (high = +84.0°C, crit = +100.0°C)

我需要在一行中以 捕获,即物理ID 0之后的温度及其单位。

所以在这里,我希望命令完全返回67.0°C

我尝试链接grep命令,这是我的尝试

sensors | grep -oEi "id[^C]+C" | grep -oEi "[\d.]+°C"

由于grep似乎无法进行分组,因此第一组用于捕获id 0: +67.0°C,第二组用于捕获67.0°C

但是,没有返回任何内容。然而,第一个grep似乎已经返回了它应该的样子。

那么如何捕获这个字符串? 如果它是bash中的一行,任何其他技术都可以。

4 个答案:

答案 0 :(得分:5)

使用awk:

sensors | awk '/^Physical id 0:/ {print $4}'

输出:

+67.0°C

答案 1 :(得分:1)

您可以使用

s='Physical id 0:  +67.0°C  (high = +84.0°C, crit = +100.0°C)'
echo $s | grep '^Physical id 0:' | awk '{print $4}'

请参阅online demo

此处,grep '^Physical id 0:'获取以Physical id 0:子字符串开头的行(请注意^是正则表达式中的行首锚点),然后awk打印列4(因为awk使用制表符和空格将行拆分为列)。

这种方法利用了这样一个事实,即你的字符串结构合理,Physical id 0:后温度总是以摄氏度为单位。

如果您需要更高的精确度并且可以访问GNU grep,则可以使用PCRE grep选项P来使用PCRE模式,例如

sensors | grep -oP 'Physical\s+id\s+\d+:\s+\K[0-9+.]+°C'

获取1位数,+.符号后跟°C

<强>详情

  • Physical - 文字子字符串
  • \s+ - 1+空格
  • id\s+ - id和1+空白
  • \d+ - 1+位数
  • : - 冒号
  • \s+ - 一个或多个空格
  • \K - 匹配重置运算符,丢弃目前为止匹配的所有文本
  • [0-9+.]+ - 一个或多个数字字符,+.
  • °C - 文字°C文字

答案 2 :(得分:1)

纯粹的打击。首先是“大”的方式来更好地理解它,然后是“oneliner”风格。

#!/usr/bin/env bash

regex=".*id 0:[ \t]+[\+\-]([0-9\.]+°C).*"
line_filter="Physical id 0"

[[ $(sensors | grep "${line_filter}") =~ ${regex} ]] && result="${BASH_REMATCH[1]}"

echo "${result}"

如果您没有设置变量并直接输入值,则只能在一行中完成。这是“oneliner”风格:

[[ $(sensors | grep "Physical id 0") =~ .*id 0:[ \t]+[\+\-]([0-9\.]+°C).* ]] && result="${BASH_REMATCH[1]}"

我改进了正则表达式以使用空格或制表符,因为我不确定两者都可以。我做的另一个小改进是加号“+”符号。它也可以是减号“ - ”符号。也许如果温度低于零,你需要它:)

答案 3 :(得分:1)

符合POSIX标准的sed解决方案,使用BRE(基本正则表达式):

$ sensors | sed -n 's/^Physical id 0:  +\([^ ]*\).*/\1/p'
67.0°

使用现代ERE(扩展正则表达式)语法和非标准-E选项 - 适用于GNU sed和BSD / macOS sed

$ sensors | sed -E -n 's/^Physical id 0:  \+([^ ]*).*/\1/p'
67.0°

请注意()需要\ - 在BRE中转义以获得语法功能,如+所示,因此仅使用+隐含 literal 使用。

相反,在ERE中()是元字符,因为+会是\,这就是为什么它需要\d - 为文字转义使用。

至于您尝试的内容

唯一的问题(不考虑效率)是您尝试使用grep

  • GNU \d根本不支持grep代表数字。
  • BSD / macOS [...]在字符集(括号表达式)(0-9)内不支持

使用\d代替$ sensor | grep -oEi "id[^C]+C" | grep -oEi '[0-9.]+°C' 67.0°C 会有效:

-P

如果grep的使用不是一个选项(仅限 GNU $ sensor | grep -oEi "id[^C]+C" | cut -d'+' -f2 67.0°C ,这会启用单遍解决方案 - 请参阅Wiktor Stribiżew's solution),一个更简单的两遍解决方案是:

create table a (a1 number, b1 number);
create table b (b1 number, a1 number);

insert into a values (1, 2);
insert into b values (3, 4);
commit;

WITH            
   SQ_Union AS (
      SELECT * FROM a
      UNION ALL 
      SELECT * FROM b
   )
SELECT * FROM SQ_Union;