2015-01-10 7 views
0

Структура А происходит несколько раз в файле, и я должен суммировать значения параметра1 отдельно в numUnitsA, numUnitsB, numUnitsC для всех случаев существования структуры.Значения сумм из разных строк в файле

structureA { 
    numUnitsA { 
     parameter1 = 2 
    }  
    numUnitsB { 
     parameter1 = 4 
    }  
    numUnitsC { 
     parameter1 = 3 
    }  
} 

Я использую ниже, чтобы получить значения, но как суммировать их, такие как:

numUnitsA parameter1=6 
numUnitsB parameter1=9 
numUnitsC parameter1=9 

код:

while read -r line 
do 
if grep -q "parameter1" "$filename"; then 
    echo $(awk 'BEGIN{FS="="}{print $2}') 
fi 
done < "$filename" 
+0

Отклоните свой код. – gsamaras

ответ

1

Попробуйте это:

awk -F'= *' '/parameter1/ { 
    if (++numUnit % 3 == 1) {par1 += $2} 
    else if (numUnit % 3 == 2) {par2 += $2} 
    else {par3 += $2} 
} 
END {print "numUnitsA parameter1=" par1 
    print "numUnitsA parameter1=" par2 
    print "numUnitsA parameter1=" par3}' "$filename" 

Нет причина для цикла действительно. Это возьмет файл в качестве аргумента и будет искать вхождения «numUnitX», получить следующую строку и добавить значение к общему значению, соответствующему X. В конце он будет печатать итоговые значения.

Альтернативный ответ:

$ cols=$(($(grep parameter1 $filename | wc -l)/3)) 
$ grep parameter1 "$filename" | sed 's/.*= //' | pr -ts"+" --columns "$cols" | bc 

Это позволит получить все значения, а затем вставьте Unit A, значения B и C рядом друг с другом на отдельных строках, разделенных символом «+» и вычислить суммы, используя bc. Вывод состоит из трех строк, содержащих итоговые значения для единиц A, B и C соответственно.

Update Ответ теперь работает, если параметр не сразу следовать numUnits тега.

Объяснение

AWK это программа, которая делит файл на записи (думать о них как строки, даже если они могут быть несколько строк) и полей (думать о них, как колонны, с предыдущим примечание все еще действительное). Разделение этих записей и полей может быть определено пользователем, но разделители по умолчанию являются новой строкой для записей и вкладкой для полей. Таким образом, структура файла определяется следующим образом:

record1: field1 field2 spaces allowed field 3 
record2: this record has only one field 

record4: the previous line was an empty record 
record5: in awk you can refer to fields using $1, $2, $3. like this: 
$1 in your code means this field $2 in code this field $3 $4 
record7: $0 is the variable for the entire record! 

Поле может быть решена с помощью $1, $2 и т.д., специальный $0 относится ко всей записи. Два простых примера для иллюстрации. Сначала мы печатаем весь файл, отображая сценарий, эквивалентный cat: awk '{print} file' or awk '{print $ 0}' file . A second example changes every record (i.e. line as default) to the literal string не макет awk : awk '{$ 0 = "don' \ '' mock awk"} 'file . Note the special care to output a' ` ,

Builtins В нашем распоряжении имеются мощные встроенные переменные awk, некоторые из которых поясняются ниже.

  • FS поле разделитель, по умолчанию FS = "\t"
  • RS Пластинка разделитель, по умолчанию RS = "\n"
  • OFS Выходной разделитель полей, по умолчанию OFS = " "
  • ORS Выходной разделитель записей, по умолчанию ORS = "\n"
  • NR Текущий номер записи , в конце это количество записей в файле.
  • NF Количество помет в этой записке.
  • FILENAME Имя файла обрабатываемого файла.

Это очень полезные переменные, при печати разделителя поля вывода OFS будет автоматически вставлен. Следующий образец кода печатает первые два поля первой строки, разделенные одним пробелом (OFS вставляется с использованием пробела). awk 'NR == 1 {print $1, $2}' file.

Структура Базовая структура AWK выглядит следующим образом:

awk -F'= ' ' 
# this is a comment (starting with #) 
# begin clause 
BEGIN { 
    # do stuff BEFORE parsing the file 
    FS = "= +" # this is also achieved using the -F flag above 
    ... 
} 
/some regex/ { 
    # code here will be executed if record contains 'some regex' 
    # example: count number of lines that match this regex 
    count++ # increment count with one 
} 
NR == 1 { 
    # code here will only be executed on the first record 
} 
{ 
    # code right here will always be executed (i.e. for every record) 
    # note the regex is missing => match every record 
    ... 
} 
# add more clauses to match certain records before the end clause: 
END { 
    # execute code AFTER all files (you can read multiple files) have been parsed 
    print count # print number of records containing our regex 
}' path/to/some/file_to_parse /another/path/to/another/file 

В основном код, завернутые в фигурных скобках выполняются, если предыдущее булевым возвращает истину, будь то регулярное выражение было найдено в записи (/regex notation/) или логическое сравнение. Когда условие отсутствует, код всегда будет выполняться.

Решение Код проанализирован

Как вы видите, мы не имеем НАЧАТЬ положение и только один пункт записи. Мы ищем записи, строки в нашем случае, содержащие буквальную строку 'parameter1'. Это именно те строки, которые содержат значения, которые мы хотели бы подвести итогами.

Мы установили разделитель полей как регулярное выражение = +, что означает знак равенства и одно или несколько пробелов. Обратите внимание, что для записей мы заинтересованы в том, это означает, что у нас есть две записи:

 paramter1 = 4 
     field1  |||field 2, 

это означает, что $2 относится теперь к 4. Обратите внимание, что $2 будет пуст в следующей записи: paramter1=4, так как после знака равенства нет места.

Теперь у нас есть переключатель случаев:

  1. numUnit эквивалентно 1 по модулю 3
  2. numUnit эквивалентно 2 по модулю 3
  3. numUnit эквивалентно 3 по модулю 3.

Обратите внимание, что у нас сначала есть if (++numUnit ..., это увеличит переменную numUnit до того, как выражение будет оценено (поэтому перед проверкой условия). Как вы можете видеть, awk не сильно типизирован, поэтому не нужно сначала объявлять numUnit.При первом увеличении awk просто предположит, что это ноль, потому что вы пытаетесь что-то добавить к нему, и он не знает, что это такое.

Так что numUnit увеличивается каждый раз, когда мы находим запись, содержащую paramter1. Поскольку первый раз numUnit оценивается в 1, затем следует шаблон 1 2 0 1 2 0 ... ', а шаблон'numUnit' равен numUnitA numUnitB numUnitC numUnitA numUnitB ..., вы можете видеть, что каждый из этих случаев обрабатывает все и только записи одного типа. Каждый случай теперь добавит значение параметра к его сумме (как вы теперь можете легко увидеть в коде).

Наконец, мы заканчиваем скрипт awk, распечатывая информацию, помните, что это выполняется только один раз, после того, как все записи были прочитаны. Это должно быть ясно.

Я настоятельно рекомендую прочитать на awk, это очень мощный язык сценариев, позволяющий создавать сложные языковые конструкции высокого уровня. Сначала это может показаться трудным, но это стоит усилий!

+0

Спасибо @ShellFish. Альтернативный ответ ищет параметр1, поэтому работает независимо от положения параметра1 в файле. Можете ли вы предложить любую модификацию в первом скрипте, чтобы сделать то же самое. – user2610

+0

@ user2610 Вы правы, я исправил проблему. Конечно, программа не будет работать так, как предполагается, если в некоторой структуре numUnitsB предшествует numUnitsA. Если это произойдет, мне придется добавить еще несколько строк. – ShellFish

+0

Спасибо [email protected] работает нормально. Поделитесь ли вы логикой, используемой в скрипте. Я новичок в написании сценариев. – user2610

Смежные вопросы