提取字母数字值

时间:2016-11-09 21:02:32

标签: bash awk grep

我有以下格式的文件

 m.dat -c16 -S32m  1.3768702014349401 s, rate:  3.2434134115834929 GB/s.
 m.dat -c16 -S64m  1.0852226612623781 s, rate:  4.115062684139847 GB/s.
 m.dat -c20 -S1m  3.8889309875667095 s, rate:  1.1483256688332133 GB/s.
 m.dat -c20 -S2m  16.622251618420705 s, rate:  0.26866151348562284 GB/s.
 m.dat -c20 -S4m  4.5505061785224825 s, rate:  0.98137637927430543 GB/s.
 m.dat -c20 -S8m  2.4563963813707232 s, rate:  1.8180124800752873 GB/s.

我想从中提取不同的数字值。特别是,我得到了类似的东西:

m.dat 20 4  4.5505061785224825  0.98137637927430543

也就是说,我想提取数字,不带字符加上文件中每行的第一个字段。

我可以轻松地使用awk获取每行的不同字段,但这些值还包括-c-S,这些不感兴趣。

awk '{print $1, $2, $3, $4}' file

7 个答案:

答案 0 :(得分:3)

这是一个棘手的perl:

$ perl -lane '@fields=(@F[0], /(\d+(?:\.\d*)?|\d*\.\d+)/g); print "@fields"' file
m.dat 16 32 1.3768702014349401 3.2434134115834929
m.dat 16 64 1.0852226612623781 4.115062684139847
m.dat 20 1 3.8889309875667095 1.1483256688332133
m.dat 20 2 16.622251618420705 0.26866151348562284
m.dat 20 4 4.5505061785224825 0.98137637927430543
m.dat 20 8 2.4563963813707232 1.8180124800752873

根据要求运行,解释。

答案 1 :(得分:2)

另一个perl解决方案

$ perl -lne 'print join "\t", /^\s*\K\S+|\d+\.\d+|\d+/g' file 
m.dat   16  32  1.3768702014349401  3.2434134115834929
m.dat   16  64  1.0852226612623781  4.115062684139847
m.dat   20  1   3.8889309875667095  1.1483256688332133
m.dat   20  2   16.622251618420705  0.26866151348562284
m.dat   20  4   4.5505061785224825  0.98137637927430543
m.dat   20  8   2.4563963813707232  1.8180124800752873
  • join "\t"使用tab作为输出分隔符,如果需要,将其更改为任何其他字符串序列
  • /^\s*\K\S+|\d+\.\d+|\d+/g正则表达式定义要提取的文本
    • ^\s*\K\S+从行的开头,不包括可选空格,获取非空格字符 - 在这种情况下获取行标签m.dat
    • \d+\.\d+.
    • 之前/之后提取至少一位数的小数
    • \d+顺序很重要,首先提取小数,然后获得非小数位数序列

答案 2 :(得分:1)

awk '{print $1,substr($2,3),substr(substr($3,3),1,length(substr($3,3))-1),$4,$7}' file

输出:

m.dat 16 32 1.3768702014349401 3.2434134115834929
m.dat 16 64 1.0852226612623781 4.115062684139847
m.dat 20 1 3.8889309875667095 1.1483256688332133
m.dat 20 2 16.622251618420705 0.26866151348562284
m.dat 20 4 4.5505061785224825 0.98137637927430543
m.dat 20 8 2.4563963813707232 1.8180124800752873

答案 3 :(得分:1)

我建议pastecutawktr的实用组合:

$ paste -d' ' <(cut -d' ' -f1 file) <(awk '{print $2, $3, $4, $7}' file | tr -dC '0-9. \n')

m.dat 16 32 1.3768702014349401 3.2434134115834929
m.dat 16 64 1.0852226612623781 4.115062684139847
m.dat 20 1 3.8889309875667095 1.1483256688332133
m.dat 20 2 16.622251618420705 0.26866151348562284
m.dat 20 4 4.5505061785224825 0.98137637927430543
m.dat 20 8 2.4563963813707232 1.8180124800752873

这不是最快的方法,但很容易理解:

  • cut -d' ' -f1 file从文件file输出第一个以空格分隔的字段。

  • awk '{print $2, $3, $4, $7 }'输出file的以空格分隔的字段2,3,4和7,在输出中以单个空格分隔。

    • tr -dC '0-9 \n'-d的输出中移除(-C)除(awk)个数字,空格和换行符之外的所有字符。
  • paste -d' ' <(...) <(...)使用两个process substitutions合并来自cut命令和awk管道输出的相应行,由单个空格分隔。< / p>

答案 4 :(得分:1)

通常不会使用用户定义的awk函数,但在这种情况下,它们允许使用简单,可扩展的解决方案:

$ awk '
function strip(val) { gsub("[^0-9.]", "", val); return val } # keep only digits and "."
{ print $1, strip($2), strip($3), $4, $7 }
' file

m.dat 16 32 1.3768702014349401 3.2434134115834929
m.dat 16 64 1.0852226612623781 4.115062684139847
m.dat 20 1 3.8889309875667095 1.1483256688332133
m.dat 20 2 16.622251618420705 0.26866151348562284
m.dat 20 4 4.5505061785224825 0.98137637927430543
m.dat 20 8 2.4563963813707232 1.8180124800752873

或者, GNU awk的{​​{1}}函数允许相对简洁的解决方案:

gensub()

答案 5 :(得分:1)

我想要最简单的想法和最少的代码奖。如果您想要的只是数字数据,请使用非数字作为分隔符:

$ awk -F '[^0-9.-]+' '{split($0, a, / +/); print a[2], $4, $6, $7, $8}' dat
m.dat 16 32 1.3768702014349401 3.2434134115834929
m.dat 16 64 1.0852226612623781 4.115062684139847
m.dat 20 1 3.8889309875667095 1.1483256688332133
m.dat 20 2 16.622251618420705 0.26866151348562284
m.dat 20 4 4.5505061785224825 0.98137637927430543
m.dat 20 8 2.4563963813707232 1.8180124800752873

要在第一个字段上添加,请将记录拆分为两种方式。

答案 6 :(得分:0)

我建议去除所有非数字值(仍然需要改进来处理.):

$ awk '{ for (i=2;i<=NF;i++) { gsub("[^0-9.]*","",$i); } gsub("\\s+", " "); $NF=""; print ; }' data.dat 
m.dat 16 32 1.3768702014349401 3.2434134115834929 
m.dat 16 64 1.0852226612623781 4.115062684139847 
m.dat 20 1 3.8889309875667095 1.1483256688332133 
m.dat 20 2 16.622251618420705 0.26866151348562284 
m.dat 20 4 4.5505061785224825 0.98137637927430543 
m.dat 20 8 2.4563963813707232 1.8180124800752873

编辑:我认为我的附加点(在正则表达式中包含.时)也是由于第一个字段也被替换了。我已相应地修改了答案。