Как найти разницу между двумя файлами, используя несколько условий?

У меня есть два файла file1.txt и file2.txt, как показано ниже -

cat file1.txt
2016-07-20-22   4343250019    1003116 001 data45343    25-JUL-16 11-MAR-16 1            N            0          0 N 
2016-06-20-22       654650018    1003116 001 data45343    25-JUL-17 11-MAR-16 1           N            0      0 N 

cat file2.txt
2016-07-20-22|9|1003116|001|data45343|25-JUL-16 11-MAR-16|1|N|0|0|N|hello|table|one
2016-06-20-22|8|1003116|001|data45343|25-JUL-17 11-MAR-16|1|N|0|0|N|hi|this|kill
2017-06-22-22|8|1003116|001|data45333|25-JUL-17 11-MAR-16|1|N|0|0|N|kill|boll|one

Требование состоит в том, чтобы получить записи, которые не доступны в file1.txt, используя условие ниже.

file1.txt                  file2.txt 
col1(date)                 col1(Date)
col2(number: 4343250019 )  col2(last value of number: 9)
col3(number)               col3(number)
col5(alphanumeric)         col5(alphanumeric)

Ожидаемый результат:

2017-06-22-22|8|1003116|001|data45333|25-JUL-17 11-MAR-16|1|NULL|0|0|N|kill|boll|one

Эта строка вывода недоступна в file1.txt, но доступна в file2.txt после удовлетворения критериям соответствия.

Я пытался ниже шагов для достижения этого результата -

###Replacing the space/tab from the file1.txt with pipe
awk '{print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10}' OFS="|" file1.txt > file1.txt1

### Looping on a combination of four column of file1.txt1 with combination of modified column of file2.txt and output in output.txt
awk 'BEGIN{FS=OFS="|"} {a[$1FS$2FS$3FS$5];next} {(($1 FS substr($2,length($2),1) FS $3 FS $5) in a) print $0}' file2.txt file1.txt1 > output.txt

###And finally, replace the "N" from column 8th and put "NULL" if the value is "N".
awk -F'|' '{ gsub ("N","NULL",$8);print}' OFS="|" output.txt >  output.txt1

В чем проблема?

Моя вторая операция не работает, и я пытаюсь объединить все три операции в одну.

3 ответа

Решение

вход

$ cat f1
2016-07-20-22   4343250019    1003116 001 data45343    25-JUL-16 11-MAR-16 1            N            0          0 N 
2016-06-20-22       654650018    1003116 001 data45343    25-JUL-17 11-MAR-16 1           N            0      0 N 

$ cat f2
2016-07-20-22|9|1003116|001|data45343|25-JUL-16 11-MAR-16|1|N|0|0|N|hello|table|one
2016-06-20-22|8|1003116|001|data45343|25-JUL-17 11-MAR-16|1|N|0|0|N|hi|this|kill
2017-06-22-22|8|1003116|001|data45333|25-JUL-17 11-MAR-16|1|N|0|0|N|kill|boll|one

Выход

$ awk 'FNR==NR{a[$1,substr($2,length($2)),$3,$5];next}!(($1,$2,$3,$5) in a)' f1 FS="|" f2
2017-06-22-22|8|1003116|001|data45333|25-JUL-17 11-MAR-16|1|N|0|0|N|kill|boll|one

объяснение

awk '                                          # call awk.
 FNR==NR{                                      # This is true when awk reads first file
           a[$1,substr($2,length($2)),$3,$5]   # array a where index being $1(field1), last char from $2, $3 and $5
           next                                # stop processing go to next line
        }
        !(($1,$2,$3,$5) in a)                  # here we check index $1,$2,$3,$5 exists in array a by reading file f2
       ' f1 FS="|" f2                          # Read f1 then 
                                               # set FS and then read f2
  • FNR==NR Если количество записей, прочитанных к настоящему времени в текущем файле
    равно количеству записей, прочитанных до сих пор во всех файлах,
    условие, которое может быть истинным только для первого чтения файла.

  • a[$1,substr($2,length($2)),$3,$5] заполнить массив "a" таким образом, чтобы он индексировался первым полем, последним символом второго поля, третьим полем и пятым полем из текущей записи file1

  • next Перейдите к следующей записи, чтобы мы не выполняли никакой обработки, предназначенной для записей из второго файла.

  • !(($1,$2,$3,$5) in a) ЕСЛИ массив a индекс, построенный из полей ($1,$2,$3,$5) текущей записи file2 не существует в массиве a мы получаем логическое значение true ( ! Вызывается логическим оператором НЕ. Он используется для изменения логического состояния своего операнда. Если условие истинно, оператор Logical NOT сделает его ложным, и наоборот.) Поэтому awk выполняет операцию по умолчанию print $0 из файла2

  • f1 FS="|" f2 читать файл1 (f1), установите разделитель полей "|" после прочтения первого файла, а затем чтения файла2 (f2)

--редактировать--

Когда размер файла составляет около 60 ГБ (900 миллионов строк), не рекомендуется обрабатывать файл два раза. 3-я операция - (замените "N" на "NULL" из столбца "8 ""awk -F'|' '{ gsub ("N","NULL",$8);print}' OFS="|" output.txt

$ awk 'FNR==NR{
         a[$1,substr($2,length($2)),$3,$5];
         next
      }
     !(($1,$2,$3,$5) in a){ 
         sub(/N/,"NULL",$8); 
         print
     }' f1 FS="|" OFS="|" f2

2017-06-22-22|8|1003116|001|data45333|25-JUL-17 11-MAR-16|1|NULL|0|0|N|kill|boll|one
awk -F'[|]|[[:blank:]]+' 'FNR==NR{E[$1($2%10)$3$5]++;next}!($1$2$3$5 in E)' file1.txt file2.txt

и ваш пример вывода неправильный, он должен быть (последнее поле, если отличается: data45333)

2016-07-20-22|9|1003116|001|data45333|25-JUL-16 11-MAR-16|1|N|0|0|N|hello|table|one
2017-06-22-22|8|1003116|001|data45343|25-JUL-17 11-MAR-16|1|N|0|0|N|kill|boll|one

Код комментария

# separator for both file first with blank, second with `|`
awk -F'[|]|[[:blank:]]+' '
   # for first file
   FNR==NR{
      # create en index entry based on the 4 field. The forat of filed allow to use them directly without separator (univoq)
      E[ $1 ( $2 % 10 ) $3 $5 ]++
      # for this line (file) don't go further
      next
      }

   # for next file lines

   # if not in the index list of entry, print the line (default action)
   ! ( ( $1 $2 $3 $5 ) in E ) { print }
   ' file1.txt file2.txt

Вы можете попробовать это awk:

awk -F'[ |]*' 'NR==FNR{su=substr($2,length($2),1); a[$1":"su":"$3":"$5]=1;next} !a[$1":"$2":"$3":"$5]{print $0}' f1 f2

Вот,

  • a[] - ассоциативный массив
  • $1":"su":"$3":"$5 - это формирует ключ для индекса массива. su последняя цифра поля $2 (su=substr($2,length($2),1)). Затем, присваивая 1 в качестве значения для этого ключа.
  • NR==FNR{...;next} - этот блок работает на обработку f1,

Обновить:

awk 'NR==FNR{$2=substr($2,length($2),1); a[$1":"$2":"$3":"$5]=1;next} !a[$1":"$2":"$3":"$5]{gsub(/^N$/,"NULL",$8);print}' f1 FS="|" OFS='|' f2
Другие вопросы по тегам