Сравнивать два файла по определенным столбцам только построчно

мы можем сделать с самим awk...

Попробуйте ниже,

awk '{j[$0]++} END {for (i in j) print i","j[i]}' words.txt
4
23.11.2020, 21:55
3 ответа

Если я правильно понял:

  • вы хотите выполнить цикл for для всех полей :for (i=1;i<=NF;i++ ){... }
  • и внутри :вы хотите ПРОПУСТИТЬ, когда i является одним из 4 значений (в awk, «продолжить» пропустит оставшуюся часть текущего цикла for и перейдет к следующей итерации

Простой способ :Если вы хотите иметь возможность пропускать поля, вы можете сделать это, используя следующую технику

BEGIN { skip[2]++; skip[3]++; skip[22]++; skip[23]++ }

....
 for(i=1;i<=NF;i++) {
   if (i in skip) { continue ; rem="Will skip for values defined in skip array indexes" }
  ...

Вместо того, чтобы определять «пропустить» в разделе BEGIN, вы также можете иметь файл с 4 индексами, которые нужно пропустить (1 в каждой строке ), и прочитать этот файл с использованием условия NR==FNR, заполнение массива пропуска этим, а затем, когда NR!=FNR (при чтении исходного файла ), вы используете описанный выше метод, чтобы пропустить эти поля.

2
18.03.2021, 22:47

По сути, вы выполняете построчное сравнение двух файлов и определенных столбцов, исключая некоторые столбцы; это все, что вы можете сделать с GNU awkдля поддержки границ слова -\<и\>:

awk -F, -v skip='2,4,7' 'BEGIN{ filetwo=ARGV[1]; ARGV[1]=""; };{
    getline lf2 <filetwo; split(lf2, arr, ",");
    for (i=1; i<=NF; i++) {
        if ( (skip !~ "\\<"i"\\>") && $i!=arr[i] ) {
            print "Line#"FNR, "Column#" i " is different in two files."; mismatch=1; };
    };
}; mismatch { print $0; print lf2; mismatch=0; };' file2 file1

Или в любых awkверсиях:

awk -F, -v skip_cols='2,4,7' '
    BEGIN{ filetwo=ARGV[1]; ARGV[1]=""; split(skip_cols, skip, ","); };{
    getline lf2 <filetwo; split(lf2, arr, ",");
    for (i=1; i<=NF; i++) {
        if ( !(i in skip) && $i!=arr[i] ) {
            print "Line#"FNR, "Column#" i " is different in two files."; mismatch=1; };
    };
}; mismatch { print $0; print lf2; mismatch=0; };' file2 file1

объяснение кода:

  • БлокBEGIN {... }:
    это выполняется в самом начале и один раз до того, как awkнужно прочитать любой ввод.

    • Использование ARGV ,filetwo=ARGV[1];:
      прочитать второй аргумент, переданный команде (, то есть file2), и сохранить его в переменной filetwo; первый аргумент ARGV[0]— это сам awk , а третий ARGV[2]file1.
    • после того, как мы читаем значение параметра, с помощью ARGV[1]=""мы сбрасываем его значение, поэтому awk не найдет этот параметр(file2)для чтения.
    • skip="2 4 7";:
      мы определили переменную(см. Выражения присваивания)skipи установили номер столбца, который мы хотим игнорировать позже.
  • getlineкоманда-см. Использование getlineв переменную из файла:
    мы читаем строку из файла2 и присваиваем ее переменнойlf2(обратите внимание выше, что переменная filetwoтеперь содержит имя второго аргумента, который мы читаем изARGV[1])

  • split()функция:
    мы разделяем строку, которую мы читаем из file2 , которая находится в переменной lf2на символ запятой ,и сохраняем в массиве с именем arr.; теперь каждое поле этой строки адресуетсяarr[1](первым полем ),arr[2](вторым полем ),arr[3](третьим )и т. д.

  • В оператореfor-loopмы проверяем две вещи ниже:

    • Значение переменной i, указывающее номер столбца, не видно ! ~в пределах skipзначения переменной(skip !~ "\\<"i"\\>"; \<и \>являются якорями границ слов, специфичными для GNU awk, поэтому i=2не будет совпадать с22); следующий
    • проверка того, что значение столбца из файла1 не равно значению того же столбца из файла2 с теми же индексами:$i!=arr[i]; если они не совпадают, напечатайте несоответствующий номер строки FNRи индекс столбца diff i, а также установите управляющую переменную mismatch=1.
  • mismatch { print... }:печатать обе строки из файла1, а затем строку из файла2 в lf2, только если было обнаружено несоответствие и переменная mismatchбыла установлена ​​в операторе if; и сбросьте переменную mismatch=0для следующей строки.

3
18.03.2021, 22:47
$ cat tst.awk
BEGIN {
    FS=","
    split("2,4,7",tmp)
    for (i in tmp) {
        skipFldNrs[tmp[i]]
    }
}
NR==FNR {
    old[FNR] = $0
    next
}
FNR == 1 {
    for (fldNr=1; fldNr<=NF; fldNr++) {
        if ( !(fldNr in skipFldNrs) ) {
            chkFldNrs[++numToChk] = fldNr
        }
    }
}
old[FNR] != $0 {
    split(old[FNR],o)
    for (i=1; i<=numToChk; i++) {
        fldNr = chkFldNrs[i]
        if ( o[fldNr] != $fldNr ) {
            printf "Line#%d, column:%d is different in two files (\"%s\" vs \"%s\").\n", FNR, fldNr, o[fldNr], $fldNr
        }
    }
}

$ awk  -f tst.awk f1 f2
Line#1, column:3 is different in two files ("col3" vs "col03").
Line#1, column:6 is different in two files ("col6" vs "col06").
Line#2, column:5 is different in two files ("col15" vs "col015").
1
18.03.2021, 22:47

Теги

Похожие вопросы