2016-11-09 2 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' разбивает каждую строку ввода на массив полей по пробелу, что дает доступ к 1-му полю как '@F [0]' , Затем вы объединяете это 1-ое поле с массивом числовых токенов в строке, полученным с помощью регулярного выражения, для формирования выходного массива '@ fields'. Передавая '@ fields' внутри двойных кавычек для' print', элементы массива преобразуются в строку с одним пробелом между элементами. Regex '/ .../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 

Edit: я фигурировал дополнительная точка, которую я имел (при включении . в regexp) было связано с заменой первого поля. Я соответствующим образом изменил ответ.

+2

Хорошая идея, удаляющая нечисловые числа, но вам нужно сделать это только для столбцов 2 и 3 (что позволяет избежать проблемы '.'). И вы также можете упростить печать: 'awk '{for (i = 2; i <= 3; i ++) gsub (" [^ 0-9] "," ", $ i); print $ 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

Я предлагаю прагматическое сочетание paste, cut, awk и tr:

$ 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 выводит 1-ое пространство разделенного поля из файла file.

  • awk '{print $2, $3, $4, $7 }' выходы file поля с пробелами 2, 3, 4 и 7, разделенные пробелом на выходе.

    • tr -dC '0-9 \n' удаляет (-d) все символы кроме (-C) цифры, пробелы и переводы строк из вывода awk «s.
  • 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 

В качестве альтернативы, GNU «ы gensub()awk функция допускает относительно сжатое решение:

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 К. Лоуден, и если я тоже хочу первое поле? – Manolete