2016-03-14 3 views
1

У меня есть небольшой скрипт для сравнения некоторых столбцов внутри кучи файлов CSV. Он работает нормально, но есть некоторые вещи, которые меня прослушивают.Используйте AWK для печати FILENAME CSV

Вот код:

FILES=./* 
for f in $FILES 

do 
    cat -v $f | sed "s/\^A/,/g" > op_tmp.csv 
    awk -F, -vOFS=, 'NR == 1{next} $9=="T"{t[$8]+=$7;n[$8]} $9=="A"{a[$8]+=$7;n[$8]} $9=="C"{c[$8]+=$7;n[$8]} $9=="R"{r[$8]+=$7;n[$8]} $9=="P"{p[$8]+=$7;n[$8]} END{ for (i in n){print i "|" "A" "|" a[i]; print i "|" "C" "|" c[i]; print i "|" "R" "|" r[i]; print i "|" "P" "|" p[i]; print i "|" "T" "|" t[i] "|" (t[i]==a[i]+c[i]+r[i]+p[i] ? "ERROR" : "MATCHED")} }' op_tmp.csv >> output.csv 
    rm op_tmp.csv 
done 

Просто объяснить: я получаю все файлы в каталоге, то я использовать CAT заменить делитель^А для труб |. Затем я использую awk onliner для сравнения столбцов, которые мне нужны, и распечатайте результат на output.csv.

Но теперь я хочу напечатать имя файла перед каждым циклом. Я попытался с помощью кота SED и AWK в той же строке и печать $ FILENAME, но он не работает:

cat -v $f | sed "s/\^A/,/g" | awk -F, -vOFS=, 'NR == 1{next} $9=="T"{t[$8]+=$7;n[$8]} $9=="A"{a[$8]+=$7;n[$8]} $9=="C"{c[$8]+=$7;n[$8]} $9=="R"{r[$8]+=$7;n[$8]} $9=="P"{p[$8]+=$7;n[$8]} END{ for (i in n){print i "|" "A" "|" a[i]; print i "|" "C" "|" c[i]; print i "|" "R" "|" r[i]; print i "|" "P" "|" p[i]; print i "|" "T" "|" t[i] "|" (t[i]==a[i]+c[i]+r[i]+p[i] ? "ERROR" : "MATCHED")} }' > output.csv 

Может кто-нибудь помочь?

ответ

1

Вы можете переписать весь сценарий лучше, но при условии, что делает то, что вы хотите сейчас просто добавить

echo $f >> output.csv

до того AWK вызова.

Если вы хотите добавить имя файла в каждой выходной AWK линии, вы должны передать его в качестве аргумента, т.е.

awk ... -v fname="$f" '{...; print fname... etc 
1

переписывание:

for f in ./*; do 
    awk -F '\x01' -v OFS="|" ' 
     BEGIN { 
      letter[1]="A"; letter[2]="C"; letter[3]="R"; letter[4]="P"; letter[5]="T" 
      letters["A"] = letters["C"] = letters["R"] = letters["P"] = letters["T"] = 1 
     } 
     NR == 1 {next} 
     $9 in letters { 
      count[$9,$8] += $7 
      seen[$8] 
     } 
     END { 
      print FILENAME 
      for (i in seen) { 
       sum = 0 
       for (j=1; j<=4; j++) { 
        print i, letter[j], count[letter[j],i] 
        sum += count[letter[j],i] 
       } 
       print i, "T", count["T",i], (count["T",i] == sum ? "ERROR" : "MATCHED") 
      } 
     } 
    ' "$f" 
done > output.csv 

Примечания:

  • ваш метод итерации над файлами будет разорваться, как только у вас будет имя файла с пробелом в нем
  • попытайтесь уменьшить дублирование как можно больше.
  • новой строки свободны, использовать их, чтобы улучшить читаемость
  • улучшить ваши имена переменных i, n и т.д. - здесь «буква» и «письма» могли бы использовать улучшение провести некоторые смысл об этих символах.
  • AWK имеет FILENAME переменную (вот фактический ответ на ваш вопрос)
  • AWK понимает \x01 быть Ctrl-A - Я предполагаю, что это поле разделитель входных файлов
  • определить Поле вывода Сепаратор, что вы на самом деле использовать

Если у вас есть GNU AWK (версия ???), вы можете использовать ENDFILE блок и покончит с петлей оболочки for вообще:

gawk -F '\x01' -v OFS="|" ' 
    BEGIN {...} 
    FNR == 1 {next} 
    $9 in letters {...} 
    ENDFILE { 
     print FILENAME 
     for ... 
     # clean up the counters for the next file 
     delete count 
     delete seen 
    } 
' ./* > output.csv 
+0

Даже без gawk вы могли бы, наряду с несколькими другими настройками, поместить этот блок END в функцию и вызвать его в условиях «FNR == 1» и «END», и вам не понадобится цикл оболочки. 'ENDFILE' появился в gawk 4.0 btw, см. Http://www.gnu.org/software/gawk/manual/gawk.html#Feature-History. –

+0

Это переработанное произведение, в конце концов я буду обновлять что-то подобное, но прямо сейчас я только что скорректировал с помощью переменной $ fname и печати перед каждым циклом. Также удалены временный файл и кошка. Большое спасибо. –

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