如何从问题中的输出中提取第一列中的正数?

如何从问题中的输出中提取第一列中的正数?

我正在运行 Ubuntu 14.04.1 LTS 64 位,Bash 4.3.11(1)-release我有一个名为harminv生成输出的程序,如下所示:

$ h5totxt hsli0.126.h5 | harminv -vt 0.1 -w 2-3 -a 0.9 -f 200 
# harminv: 1902 inputs, dt = 0.1
frequency, decay constant, Q, amplitude, phase, error
# searching frequency range 0.31831 - 0.477465
# using 200 spectral basis functions, density 6.60692
-2.14026, 3.511909e-05, 30471.5, 0.922444, 1.26783, 1.383955e-06
2.14013, 2.052504e-05, 52134.7, 0.920264, -1.27977, 3.426846e-07
# harminv: 2/6 modes are ok: errs <= 1.000000e-01 and inf * 3.426846e-07
, amps >= 0, 9.000000e-01 * 0.922444, |Q| >= 10

-v省略(详细)选项时,我会得到更简洁的输出,如下所示:

$ h5totxt hsli0.126.h5 | harminv -t 0.1 -w 2-3 -a 0.9 -f 200 
frequency, decay constant, Q, amplitude, phase, error
-2.14026, 3.511909e-05, 30471.5, 0.922444, 1.26783, 1.383955e-06
2.14013, 2.052504e-05, 52134.7, 0.920264, -1.27977, 3.426846e-07

我希望能够在两种情况下提取输出第一列中的正数,但不知道如何做到这一点,除了我可以使用sedor awk。如果有人为我指出正确的方向,我将不胜感激,我的目标是记录每个正数以针对其他变量绘制图表。

答案1

使用 sed

这将仅打印以正数开头的行:

sed -n 's/^\([[:digit:]][^ ,]*\).*/\1/p'

与您的管道之一相结合,它看起来像:

h5totxt hsli0.126.h5 | harminv -vt 0.1 -w 2-3 -a 0.9 -f 200 | sed -n 's/^\([[:digit:]][^ ,]*\).*/\1/p'

怎么运行的

  • -n

    这告诉sed我们不要打印任何行,除非我们明确要求它。

  • s/^\([[:digit:]][^ ,]*\).*/\1/p

    这告诉sed我们寻找以正数开头的行并仅打印该数字。

    在正则表达式中,^仅匹配行的开头。 [[:digit:]]匹配任何数字。 [^ ,]*匹配该数字后面的任何内容(空格或逗号除外)。这些都用括号分组,以便我们稍后可以将数字称为\1。然后整行被数字替换,并且通过选项p,我们告诉sed打印它。

    一个用来[0-9]匹配数字。随着 unicode 字体的出现,这种情况不再可靠。[[:digit:]]然而,表达式是 unicode 安全的。

使用扩展正则表达式的替代方案

如果您使用 GNU sed(所有 Linux 系统都是如此),那么该-r选项可用于获取扩展正则表达式。使用扩展正则表达式,用于分组的括号不需要转义:

sed -rn 's/^([[:digit:]][^ ,]*).*/\1/p'

在 OSX 或其他 BSD 系统上,使用-E代替-r.

使用 awk

其作用相同,但使用awk

awk -F, '/^[[:digit:]]/{print $1}'

与您的管道相结合:

h5totxt hsli0.126.h5 | harminv -vt 0.1 -w 2-3 -a 0.9 -f 200 | awk -F, '/^[[:digit:]]/{print $1}'

答案2

鉴于您显示的输入,以下内容应该有效:

sed -n 's/[^[:digit:]]/\
&/;/.\n/P'

...或者...

sed 's/[^[:digit:]].*//;/./!d'

...对于一些seds 你也可以这样写...

sed -n 's/[^0-9]/\n&/;/.\n/P'

...或者...

sed 's/[^0-9].*//;/./!d'

...甚至可能 - 取决于您的输入数据集 - 使用 GNU sed,例如...

sed -n 's/\W/\n&/;/.\n/P'

...或者...

sed 's/\W.*//;/./!d'

因为正则语言基本上是补集的描述,所以您几乎总是可以彻底改变正则表达式。有时这样做会减少工作量。

因此,如果您在字符串的头部搜索长度未知的特定模式,则只需查找与您的模式不匹配的字符串的第一部分可能会更简单。

上面的第一个示例\n在一行中遇到的第一个非数字字符之前插入一个 ewline 字符。然后它检查是否这样做了(如果这样做的话),插入内容与行首之间至少有一个字符。如果不是,则不打印,但如果是,则仅打印到\n插入的行。

下一个示例类似 - 它只是从以与模式不匹配的字符开头的行中剥离最长的字符串,然后从输出中删除所有空白行。

其余的只是简写,用于执行更多与某些 s 可能解释的相同的操作sed,尽管前两个非常严格地遵守 POSIX sed语法规范(虽然这可能[[:digit:]]有点过头了,因为据我了解,UTF-8 是 ASCII 超集,并且大多数不包含阿拉伯数字的语言也与我编写此代码的语言有很大不同,需要其他修改才能使其可行反正)

所有示例(取决于注释中的实现和输入)应仅打印从行首开始的第一个连续数字匹配序列。

不过,考虑一下 - 因为你似乎无论如何都在空格和逗号上进行分隔 - 我想它也可以写成:

sed -n 'y/, -/\n\n\n/;/^[0-9]/P'

...几乎没有任何实际的正则表达式匹配 - 作为y///函数翻译字符而不是按照模式对它们进行分组。正则表达式匹配器仅用于测试结果。

相关内容