AWK конвертация файлов - PullRequest
       7

AWK конвертация файлов

0 голосов
/ 06 сентября 2018

У меня есть файл в следующем формате:

Total:89.3    
User: user1
    Count:3
    Sum:80
      departmentId: dept1
      Amount by departmentId: 20
      departmentId: dept1
      Amount by departmentId: 35
      departmentId: dept2
      Amount by departmentId: 25
    User: user2
    Count:3
    Sum:7.199999999999999
      departmentId: dept1
      Amount by departmentId: 2.4
      departmentId: dept2
      Amount by departmentId: 2.4
      departmentId: dept3
      Amount by departmentId: 2.4
    User: user3
    Count:1
    Sum:0.2
      departmentId: dept2
      Amount by departmentId: 0.2
    User: user4
    Count:2
    Sum:2
      departmentId: dept3
      Amount by departmentId: 1
      departmentId: dept3
      Amount by departmentId: 1

Список файлов в основном Пользовательский сбор за отдел. Если один и тот же пользователь связан с отделом несколько раз, его необходимо объединить в один ряд. Выходной файл должен быть в следующем формате. Для пользователя 1 он имеет 2 взноса для dept1 и 1 взнос для dept2. Таким образом, в выходном файле 2 сбора для dept1 должны быть объединены в 1 счет должен быть нет. уникального пользователя на отдел.

Format:
count_of_uique_user_dept_rows total_sum   -- note** header row-->total sum and total no. of unique user dues
userId+deptId sum for that dept

Example:

7 89.3
user1dept1 55
user1dept2 25
user2dept1 2.4
user2dept2 2.4
user2dept3 2.4
user3dept2 0.2
user4dept3 2

что у меня до сих пор,

# This awk script is used to convert the input of library credit/debit's to the required Student Accounts Load format
BEGIN { FS=": *" }
{
    gsub(/^ +| +$/,"")
    f[$1] = $2

}
/Amount/ {
    dept = f["departmentId"]
    total = f["Total"]
    sum[dept] += $2
    amount += $2

}
$1 == "User" {
    if (NR>1) {
        format()
    }
    user = $2
}
END { format() }

function format() {
if ( length(sum) > 0 ) {
    for (dept in sum) {
        printf "%-9s%-12s%10.2f\n", substr(user,1,9), substr(dept,1,12), sum[dept]
    }
    delete sum
    amount = 0
 }
}

Приведенный выше скрипт дает нам строку данных. Я не могу понять, как получить строку заголовка 7 89.3 Пожалуйста, помогите.

Ответы [ 2 ]

0 голосов
/ 06 сентября 2018

Использование GNU awk и 2d массивов:

$ awk '
$1=="User:" {                                 # store user
    u=$NF 
}
$1=="departmentId:" {                         # store dept
    d=$NF
}
$1=="Amount" {
    if(a[u][d]=="")                           # count uniq user/depts
        c++
    s+=$NF                                    # total sum
    a[u][d]+=$NF                              # user/dept sum
}
END {
    printf "%s, %.2f\n",c,s                   # output count and total
    for(u in a)
        for(d in a[u]) 
            printf "%s %s %.2f\n",u,d,a[u][d] # output user/dept sums
}' file

Выход:

7 89.40
user1 dept1 55.00
user1 dept2 25.00
user2 dept1 2.40
user2 dept2 2.40
user2 dept3 2.40
user3 dept2 0.20
user4 dept3 2.00
0 голосов
/ 06 сентября 2018

Я решил не читать файл дважды, а просто сохранить выходные данные в массиве перед печатью. Вот как это сделать:

Шаг 1: исправьте синтаксическую ошибку, которую вы получите от некоторых awk, когда они предполагают, что sum является скаляром из-за того, что вы вызвали length(sum) до того, как он был использован в качестве массива, добавив операцию массива delete sum в раздел BEGIN (вы можете просто удалить тест на длину (сумму), поскольку он не делает ничего полезного в вашем коде, но я хотел объяснить проблему и как ее решить в целом).

BEGIN { FS=": *"; delete sum }

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

function format() {
if ( length(sum) > 0 ) {
    for (dept in sum) {
        vals[++numVals] = sprintf("%-9s%-12s%10.2f", substr(user,1,9), substr(dept,1,12), sum[dept])
    }
    delete sum
    amount = 0
 }

}

Шаг 3: добавьте цикл в разделе КОНЕЦ, чтобы на самом деле печатать:

END {
    format()
    for (valNr=1; valNr<=numVals; valNr++) {
        print vals[valNr]
    }
}

На этом этапе вы получите тот же результат, что и ваш существующий скрипт, но он настроит нас на добавление новых необходимых вам функций:

Шаг 4: сохранить каждую комбинацию пользователь + отдел как индексы массива usrdpt[]:

/Amount/ {
    dept = f["departmentId"]
    total = f["Total"]
    sum[dept] += $2
    usrdpt[user,dept]
    amount += $2
}

Шаг 5: напечатайте количество уникальных индексов нового массива usrdpt[] в разделе END перед печатью предыдущих значений:

END {
    format()
    print length(usrdpt)
    for (valNr=1; valNr<=numVals; valNr++) {
        print vals[valNr]
    }
}

Результат:

$ cat tst.awk
BEGIN { FS=": *"; delete sum }
{
    gsub(/^ +| +$/,"")
    f[$1] = $2
}
/Amount/ {
    dept = f["departmentId"]
    total = f["Total"]
    sum[dept] += $2
    usrdpt[user,dept]
    amount += $2
}
$1 == "User" {
    if (NR>1) {
        format()
    }
    user = $2
}
END {
    format()
    print length(usrdpt)
    for (valNr=1; valNr<=numVals; valNr++) {
        print vals[valNr]
    }
}

function format() {
if ( length(sum) > 0 ) {
    for (dept in sum) {
        vals[++numVals] = sprintf("%-9s%-12s%10.2f", substr(user,1,9), substr(dept,1,12), sum[dept])
    }
    delete sum
    amount = 0
 }
}

.

$ awk -f tst.awk file
7
user1    dept1            55.00
user1    dept2            25.00
user2    dept1             2.40
user2    dept2             2.40
user2    dept3             2.40
user3    dept2             0.20
user4    dept3             2.00

Полагаю, вы сможете выяснить, как сохранить, а затем распечатать значение Total.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...