我应该使用哪个工具从字符串中提取数据?

时间:2012-09-09 19:58:24

标签: linux bash sed awk

作为一个非常新的Linux用户,我从未(真的)使用sedawk(或任何其他)等工具来解析文本。 我想从

中提取
  

速度:1624.127424 Kib / s,9.410000秒

第二个时间值,就在seconds字之前,

我应该考虑哪个工具?

5 个答案:

答案 0 :(得分:6)

您可以使用许多工具,但awk会很好:

echo "Speed : 1624.127424 Kib/s in 9.410000 seconds" | awk '{print $6}'

或(如果您的数据在文件中):

awk '{print $6}' data.txt

给你

9.410000

解释

这假设您感兴趣的值在线上的相对位置将保持不变(在这种情况下是第6个白色空格分隔字段),相应地进行调整。

awk将输入行拆分为基于空白的字段。您感兴趣的字段是第6个字段,因此您使用$6打印该字段。

或者,您也可以使用awk '{print $(NF-1)}'打印行上的倒数第二个字段(NF是一个awk变量,它知道给定行上的字段数)。这提供了更多的灵活性,因为它可以使用长度线(即字段数),只要您感兴趣的字段是倒数第二个。

-

cut也是另一种可行的工具:

echo "Speed : 1624.127424 Kib/s in 9.410000 seconds" | cut -d' ' -f 6

在这种情况下,该行根据空格的分隔符(由-d指定)进行拆分,我们再次感兴趣的是第6个字段(-f 6)。

还有其他方法,但这两个看起来很直接,首先想到了。

答案 1 :(得分:3)

或者,如果您不确切地知道字符串中的确切位置,但您知道它在“秒”之前,则可以使用sed。这会进入正则表达式,它不像计算字段那样简单,但它们可以让您从可能没有这种严格约束格式的字符串中获取数据。这是一种方式(<<<只是另一种方式来输入字符串作为命令的输入):

sed -n 's/^.* \([0-9.]\+\) seconds.*$/\1/p'  <<<"Speed : 1624.127424 Kib/s in 9.410000 seconds" 

由于只有一行输入,-n/p在这里是无关紧要的,但它们形成了一个有用的模式:它们告诉sed默认不打印所有行,但只有搜索和替换成功的那些。

s/old/new/语法执行搜索和替换,其中“旧”部分是正则表达式模式。

模式[0-9.]\+ seconds匹配一个或多个数字或句点,后跟空格和单词“秒”。在模式的一部分周围放置反斜杠括号会使匹配模式部分的实际字符串保存在变量中供以后使用;所以\([0-9.]\+\) seconds会捕获所需的数字。

由于我们只想打印 这个值,我们将它放在^.*.*$之间,.*匹配'从行开始的所有内容',\1匹配'直到行结束的一切'。这样整个生产线都将被替换。但是,由于sed是贪婪的,如果我们把它放在模式的前面,它会咀嚼我们号码的最后一位数字,这是我们不想要的。将数字前的空格添加到模式可以防止这种情况。

我们用什么替换线?使用perl -lne 'print $1 if /([0-9.]+) seconds/' <<<"Speed : 1624.127424 Kib/s in 9.410000 seconds" ,这是与(第一对)反斜杠括号之间的模式部分匹配的字符串。

已编辑添加:

问题中未列出Perl,但与上述{{1}}方法类似的是:

{{1}}

答案 2 :(得分:2)

如果变量中有一个字符串,则可以使用shell本身。如果你知道它是第六个字段(比如@ Levon的awk解决方案假设),你可以这样做:

set -- $variable
seconds=$6

或者,如果您知道单词seconds后跟单词,则可以使用字符串替换;

prefix=${variable%\ seconds*}
seconds=${prefix##*\ }

(临时变量包含原始空格后的任何内容,“秒”被修剪掉。我们同样会从开头的最后一个空格中修剪所有内容。)

不要低估贝壳,它非常通用,虽然有时很古怪。

答案 3 :(得分:2)

只是为了完成,perl可以在类似awk的模式下运行。假设您的数据是data.txt

$ perl -lane 'print $F[5] data.txt'
9.410000

-a打开autosplit模式 - perl会自动将空格上的输入行拆分为@F数组。

答案 4 :(得分:1)

此外,cut

echo "Speed : 1624.127424 Kib/s in 9.410000 seconds" | cut -f 6 -d' '

文档(摘录):

  

cut - 从每行文件中删除部分

     

<强> -d, --delimiter=DELIM

     

使用DELIM代替TAB进行字段分隔符

     

<强> -f, --fields=LIST

     

仅选择这些字段;除非指定了-s选项,否则还会打印任何不包含分隔符的行