2016-11-09 85 views
3

我有文件的格式如下提取字母數字值

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 

回答

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 

總得來看,應要求解釋。

+0

管道輸出到'column -t'使其變得很漂亮 –

+0

請允許我解釋:'-a'將每個輸入行以空格分隔爲一個字段數組,這使得第一個字段的訪問權限爲@F [0] 。然後,將第1個字段與行中的數字標記數組結合起來,使用正則表達式構造輸出數組「@ fields」。通過將雙引號內的'@ fields'傳遞給'print',數組元素被轉換爲元素之間具有單個空格的字符串。正則表達式'/ .../g'作爲一個整體隱式應用於輸入行,並將所有('g')匹配返回爲一個數組。至少在樣本輸入中,更簡單的'/ \ d +(?:\。\ d +)?/ g'也可以工作。 – mklement0

+1

謝謝@ mklement0。更復雜的正則表達式捕獲沒有整數部分的分數。如果這些沒有出現在輸入中,請簡化。 –

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 
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 

編輯:我想通我有額外的一點(當包括.在正則表達式中)是由於第一個字段被替換。我相應地修改了答案。

+2

好主意剝離非數字,但你只需要做第2列和第3列(這避免了'.'問題)。你也可以簡化打印:'awk'{for(i = 2; i <= 3; i ++)gsub(「[^ 0-9]」,「」,$ i);打印$ 1,$ 2,$ 3,$ 4,$ 7}'' – jas

+0

@jas:解決了問題!我不明白爲什麼當我的正則表達式是'[^ 0-9。'''時,我又多了一個'.';我現在有! – Aif

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"使用標籤作爲輸出分隔符,如果需要的話
  • /^\s*\K\S+|\d+\.\d+|\d+/g正則表達式定義的文本以從開頭提取
    • ^\s*\K\S+它更改爲任何其他字符串序列行,不包括可選空間,得到非空格字符 - 得到我們行標籤m.dat在這種情況下與至少一個數字前/後的.
    • \d+順序是重要的,提取分數第一,然後得到的數字非小數序列
    • \d+\.\d+提取小數
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' ' <(...) <(...)合併來自cut命令的輸出和awk管道,由單個空格分隔相應的線,使用兩個process substitutions

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 

或者,GNUawkgensub()功能允許一個相對簡潔的解決方案:

awk '{ print $1, gensub("[^0-9]+", "", "g", $2), gensub("[^0-9]+", "", "g", $3), $4, $7 }' 
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 

要釘在第一場,拆分記錄兩個方面。

+1

@_James K. Lowden,如果我也想要第一個領域? – Manolete