Как найти разницу между двумя файлами, используя несколько условий?
У меня есть два файла 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" таким образом, чтобы он индексировался первым полем, последним символом второго поля, третьим полем и пятым полем из текущей записи file1next
Перейдите к следующей записи, чтобы мы не выполняли никакой обработки, предназначенной для записей из второго файла.!(($1,$2,$3,$5) in a)
ЕСЛИ массивa
индекс, построенный из полей ($1,$2,$3,$5
) текущей записи file2 не существует в массивеa
мы получаем логическое значение true (!
Вызывается логическим оператором НЕ. Он используется для изменения логического состояния своего операнда. Если условие истинно, оператор Logical NOT сделает его ложным, и наоборот.) Поэтому awk выполняет операцию по умолчаниюprint $0
из файла2f1 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