Сравните два текстовых файла и напечатайте разницу с ключом в bash сценарии оболочки - PullRequest
0 голосов
/ 19 апреля 2020

Сценарий оболочки, bash, имеет 2 больших файла размером около 1,2 ГБ данных, с ключом и значениями, мне нужно сравнить оба файла на основе ключа и сохранить разницу в значении в третьем файле, Файл 2 всегда будет подмножество файла 1, просто нужно найти значения ( для ключа ), которых нет в файле 2, и уникальные значения в файле 1.

файл 1:

test1 marco;polo;angus
test2 mike;zen;liza
test3 tom;harry;alan
test4 bob;june;janet
1332239_44557576_CONTI Lased & Micro kjd $353.50_30062020_lsdf3_no-rule 343323H;343434311H;454656556H;343343432H
1332240_44557576_CONTI Mazed & Micro kjd $353.50_30062020_lsdf3_some-rule 232324L;2226556H;343223432H

Файл 2:

test1 polo;angus
test2 mike
test4 bob;janet
1332240_44557576_CONTI Mazed & Micro kjd $353.50_30062020_lsdf3_some-rule 232324L;343223432H

Я хотел бы сравнить первые два столбца файла1 с файлом2 ( поиск по всему содержимому файла2 в первых двух столбцах ), если они совпадают выведите разницу значений. Затем найдите вторую строку файла 1 и так далее. Также должны быть напечатаны ключи, уникальные в файле 1.

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

test1 marco
test2 zen;liza
test3 tom;harry;alan
test4 june
1332239_44557576_CONTI Lased & Micro kjd $353.50_30062020_lsdf3_no-rule 343323H;343434311H;454656556H;343343432H
1332240_44557576_CONTI Mazed & Micro kjd $353.50_30062020_lsdf3_some-rule 2226556H

У меня огромные файлы, содержащие около 100 000 строк, поэтому я хотел бы ускорить выполнение. Это выполняется в сценарии оболочки, используя bash сценарии оболочки. Эти файлы file1 и file2 являются текстовыми файлами, с ключом 1332239_44557576_CONTI Lased & Micro kjd $353.50_30062020_lsdf3_no-rule и значениями: 343323H;343434311H;454656556H;343343432H

Заранее спасибо !!

Ответы [ 2 ]

1 голос
/ 19 апреля 2020

Если ваши входные файлы слишком велики, чтобы поместиться в памяти, вы можете создать набор пар тег-значение из каждой строки тег-значения в каждом входном файле, например:

$ awk 'BEGIN{FS=OFS=";"} {tag=$0; sub(/ [^; ]+(;.*|$)/,"",tag); sub(/[^;]+ /,""); for (i=1;i<=NF;i++) print tag, $i}' file2
test1;polo
test1;angus
test2;mike
test4;bob
test4;janet
1332240_44557576_CONTI Mazed & Micro kjd $353.50_30062020_lsdf3_some-rule;232324L
1332240_44557576_CONTI Mazed & Micro kjd $353.50_30062020_lsdf3_some-rule;343223432H

, а затем использовать стандартные UNIX инструменты, такие как sort и comm, чтобы получить нужные различия, а затем рекомбинировать с awk в исходные значения тегов. Вот как все это может работать:

$ cat tst.sh
#!/usr/bin/env bash

separate() {
    awk '
        BEGIN { FS=OFS=";" }
        {
            tag = $0
            sub(/ [^; ]+(;.*|$)/,"",tag)
            sub(/[^;]+ /,"")
            for (i=1; i<=NF; i++) {
                print tag, $i
            }
        }
    ' "${@:--}" | sort
}

combine() {
    awk '
        BEGIN { FS=OFS=";" }
        $1 != prev {
            printf "%s%s", ors, $1
            prev = $1
            ors = ORS
            ofs = " "
        }
        {
            printf "%s%s", ofs, $2
            ofs = OFS
        }
        END {
            printf "%s", ors
        }
    ' "${@:--}"
}

comm -23 <(separate "$1") <(separate "$2") | combine

.

$ ./tst.sh file1 file2
1332239_44557576_CONTI Lased & Micro kjd $353.50_30062020_lsdf3_no-rule 343323H;343343432H;343434311H;454656556H
1332240_44557576_CONTI Mazed & Micro kjd $353.50_30062020_lsdf3_some-rule 2226556H
test1 marco
test2 liza;zen
test3 alan;harry;tom
test4 june

и если вы в будущем захотите найти пары тег-значение в file2, но не в file1 или в обоих тогда вы просто измените comm -23 на comm -13 или comm -12.

1 голос
/ 19 апреля 2020

Не могли бы вы попробовать, написать и протестировать с показанными образцами (также учитывая, что ваши Input_file (s) не начинаются с пробелов).

awk '
BEGIN{
  OFS=";"
}
{
  match($0,/ .*/)
  line=substr($0,RSTART,RLENGTH)
  sub(/^ +/,"",line)
}
FNR==NR{
  num=split(line,array,";")
  for(i=1;i<=num;i++){
    arrayfromFile2[$1]=(arrayfromFile2[$1]?arrayfromFile2[$1] OFS:"")array[i]
  }
  delete array
  next
}
($1 in arrayfromFile2){
  num=split(arrayfromFile2[$1],temparrayChkFile2,";")
  for(i=1;i<=num;i++){
    arrayChkFile2[temparrayChkFile2[i]]
  }
  num=split(line,array,";")
  for(i=1;i<=num;i++){
    if(!(array[i] in arrayChkFile2)){
       val=(val?val OFS:"")array[i]
    }
  }
  print $1" "val
  val=""
  next
}
1
'  Input_file2  Input_file1
...