Как мне изменить большой файл с определенным столбцом и значением, используя awk? - PullRequest
0 голосов
/ 27 августа 2018

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

a|b|c|d|e|f|g
1|2|3|4|5|6|5
2|4|2|3|5|2|1

И еще один файл конфигурации с некоторыми столбцами и значениями, например:

b:5
d:6

Моя цель - изменить набор данных с помощью файла конфигурации. Результат примерно такой:

a|b|c|d|e|f|g    
1|5|3|6|5|6|5
2|5|2|6|5|2|1

Без использования «for» вне awk, как я могу завершить процесс?

Ответы [ 2 ]

0 голосов
/ 27 августа 2018

Вот как вы можете сделать это с помощью awk:

awk '
     NR == FNR { rep[$1] = $2; next } 
     FNR == 1 { for (i = 1; i <= NF; ++i) if ($i in rep) cols[i] = rep[$i] }
     FNR > 1 { for (i in cols) $i = cols[i] }
     1
' FS=':' replacements FS='|' OFS='|' dataset
  • сначала сохраните все замены key:value в массив rep
    • выберите первый файл, используя стандарт NR == FNR (общее количество строк равно номеру этого файла)
    • пропустить оставшуюся часть сценария с помощью next
  • для первой строки набора данных (второй файл), определите, какие столбцы содержат заголовки, сохранив их в cols вместе с их заменами
  • для остальных строк набора данных замените столбцы их значениями замены
  • печатать все строки второго файла, используя условие 1 (всегда true), которое запускает действие по умолчанию { print }

Обратите внимание, что, поскольку два файла имеют разные разделители, они указываются в качестве аргументов после сценария awk. FS определяет разделитель входных полей, а OFS определяет разделитель выходных полей для следующего аргумента имени файла. Аргументы должны быть прочитаны как:

# read the file 'replacements' with input field separator set to ':'
FS=':' replacements
# read the file 'dataset' with input and output field separator set to '|'
FS='|' OFS='|' dataset

Тестирование

$ cat replacements 
b:5
d:6
$ cat dataset 
a|b|c|d|e|f|g
1|2|3|4|5|6|5
2|4|2|3|5|2|1
$ awk '
>      NR == FNR { rep[$1] = $2; next } 
>      FNR == 1 { for (i = 1; i <= NF; ++i) if ($i in rep) cols[i] = rep[$i] }
>      FNR > 1 { for (i in cols) $i = cols[i] }
>      1
> ' FS=':' replacements FS='|' OFS='|' dataset
a|b|c|d|e|f|g
1|5|3|6|5|6|5
2|5|2|6|5|2|1
0 голосов
/ 27 августа 2018

Вероятно, это целесообразно сделать в следующем порядке. Сначала вы анализируете конфигурацию (предполагая, что GNU диалект awk):

gawk -F \| -v OFS=\| 'NR == FNR { # this pattern trigs inside the first file
    split($0, mapping, /:/)
    rules[mapping[1]] = mapping[2]
    next # short-circuit to skip other blocks
}

Далее в первой строке файла данных необходимо проанализировать заголовки столбцов:

FNR == 1 {
    for(i = 1; i <= NF; ++i) if($i in rules) forcedValues[i] = rules[$i]
    print
    next
}

Теперь у вас есть массив forcedValues, который для некоторых номеров столбцов от 1 до 7 (в вашем примере) содержит значения, в которые эти столбцы должны быть сброшены. Итак, теперь вы обрабатываете остальную часть файла:

{
    for(i in forcedValues) $i = forcedValues[i]
    print
}' config.txt input.txt > output.txt

(Три фрагмента кода в этом посте на самом деле являются частями одной команды оболочки и должны объединяться через переводы строки.)

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