найти строки, существующие в одном файле, а не в другом, на основе части строки - PullRequest
2 голосов
/ 26 мая 2020

У меня есть два файла A.dat и B.dat .

A.dat

112381550RSAP002839002C00000000020200600000110102020-05-26
112539961RSAP002839002C00000000020200700000140102020-05-26
140823748RSAP002839002C00000000020210200000050102020-05-26
110604754RSAP002839002C00000000020200600000110102020-05-26

B.dat

112381550RSAP002839002C00000000020200600000000102020-05-26
112539961RSAP002839002C00000000020200700000000102020-05-26
119A06559RSAP002839002C00000000020210100000000102020-05-26
119231672RSAP002839002C00000000020200900000000102020-05-26
118372226RSAP002839002C00000000020200800000000102020-05-26

Я хочу найти записи в B.dat , которых нет в A.dat , на основе первых 22 символов (в ЖИРНЫЙ ) результат должен быть ниже

<b>119A06559RSAP002839002</b>C00000000020210100000000102020-05-26
<b>119231672RSAP002839002</b>C00000000020200900000000102020-05-26
<b>118372226RSAP002839002</b>C00000000020200800000000102020-05-26

Пробовал использовать grep как показано ниже

grep -Fvxf B.dat A.dat > c.dat 

Но не нашел способа сравнить только эту часть данных.

Ответы [ 4 ]

4 голосов
/ 26 мая 2020

Не могли бы вы попробовать следующее.

awk 'FNR==NR{array[substr($0,1,22)];next} !(substr($0,1,22) in array)'  A.dat B.dat

Пояснение: Добавление подробных объяснений к вышеизложенному.

awk '                             ##Starting awk program from here.
FNR==NR{                          ##Checking condition if FNR==NR then do following.
  array[substr($0,1,22)]          ##Creating an array whose index is first 22 elements of current line.
  next                            ##next will skip all further statements from here.
}
!(substr($0,1,22) in array)       ##Checking condition if current line first 22 characters are NOT in array the print the current line.
'  A.dat B.dat                    ##Mentioning Input_file names here.
3 голосов
/ 26 мая 2020

Я бы использовал следующий метод, основанный на awk:

awk '{s=substr($0,1,22)}(FNR==NR){a[s];next}!(s in a)' A.dat B.dat

Это гарантирует, что вы всегда будете соответствовать первым 22 символам.

По сути, он делает следующее: каждый раз После чтения строки (без учета файла) создается небольшая строка s, содержащая первые 22 символа строки. Если мы обрабатываем первый файл (FNR==NR), сохраняем строку в массиве a, если мы обрабатываем второй файл, проверяем, является ли эта строка членом a, и если нет, распечатайте строку.

Вы также можете попробовать решение на основе grep, но это может привести к ложным срабатываниям, в зависимости от того, как вам нравится ваш ввод:

cut -c1-22 A.dat | grep -vFf - B.dat

Это, однако, может соответствовать первым 22 символам строк A.dat в любом месте строк B.dat (не обязательно первые 22 символа)

2 голосов
/ 27 мая 2020

Если порядок вывода не важен, вот метод grep без использования bash, sort и GNU uniq:

sort {A,A,B}.dat | uniq -uw 22

... или в оболочке POSIX :

sort A.dat A.dat B.dat | uniq -uw 22

Вывод любого метода:

118372226RSAP002839002C00000000020200800000000102020-05-26
119231672RSAP002839002C00000000020200900000000102020-05-26
119A06559RSAP002839002C00000000020210100000000102020-05-26
2 голосов
/ 26 мая 2020

Вы можете сделать это только с помощью grep и colrm следующим образом (имя файла «-» понимается как stdin, и вы можете использовать его с «-f»):

colrm 23 < A.dat | grep -F -v -f - B.dat

Если вы не на 100% уверены, что эти 22-символьные шаблоны будут совпадать только в начале строк, вам нужно добавить '^' к каждой строке вывода из colrm и исключить флаг "-F" из флагов grep, например:

colrm 23 < A.dat | sed -e 's/^/\^/;' | grep -v -f - B.dat
...