мы можем сделать с самим awk...
Попробуйте ниже,
awk '{j[$0]++} END {for (i in j) print i","j[i]}' words.txt
Если я правильно понял:
Простой способ :Если вы хотите иметь возможность пропускать поля, вы можете сделать это, используя следующую технику
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 (при чтении исходного файла ), вы используете описанный выше метод, чтобы пропустить эти поля.
По сути, вы выполняете построчное сравнение двух файлов и определенных столбцов, исключая некоторые столбцы; это все, что вы можете сделать с 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
нужно прочитать любой ввод.
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
); следующий $i!=arr[i]
; если они не совпадают, напечатайте несоответствующий номер строки FNR
и индекс столбца diff i
, а также установите управляющую переменную mismatch=1
. mismatch { print... }
:печатать обе строки из файла1, а затем строку из файла2 в lf2
, только если было обнаружено несоответствие и переменная mismatch
была установлена в операторе if
; и сбросьте переменную mismatch=0
для следующей строки.
$ 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").