Intereting Posts
Linux device-mapper & ext4: что происходит, когда таблица COW заполняется? Спасательная ценность второй строки Автоматическое добавление косой черты при навигации по символической ссылке Как подключиться к Mac OSX Maverick Shared Screen от Fedora 18? Где параметр, который запрещает дублировать историю команд? Разница между sd0 / sda, hd0 / hda Хотите напечатать NULL, если значение отсутствует как выход awk В какой файловой системе должен использоваться загрузочный раздел GRUB 2? Debian, virtualenv, IPython и matplotlib встроенные графики Как заменить часть имени хоста на xauth (OLD: как перенаправить вывод команды xauth?) Как запустить это в sudo? Как использовать регулярное выражение для соответствия шаблону, который не имеет определенной строки в конце Ошибка при запуске TMUX под CYGWIN сценарий оболочки для пакетного преобразования M4V в MP3 с использованием VLC? Отдельные рабочие пространства на каждом мониторе

Сравнение двух файлов с использованием Unix и Awk

Мне нужно сравнить два файла: File1 и File2 (разделенные пробелом), используя 4 поля (поля 1, 2, 4 и 5 из файла 1 с полями 1, 2, 4 и 5 файла2).

Логика:
Если столбец 1, 2 и 4 файла 1 соответствуют столбцам 1, 2 и 4 файла 2, и в столбце 5 есть несоответствие, то обе строки из файла 1 и файла 2 объединяются, перенаправляются в качестве вывода. Поэтому выходной файл содержит только те строки, где совпадения столбцов 1, 2 и 4 из файлов 1 и 2 и столбцы 5 не совпадают.

File1:

sc2/80 20 . AT 86 PASS N=2 F=5;U=4 sc2/60 55 . GT 76 PASS N=2 F=5;U=4 sc2/68 20 . TC 71 PASS N=2 F=5;U=4 sc2/24 24 . TG 31 PASS N=2 F=5;U=4 

File2:

 sc2/80 20 . AC 80 PASS N=2 F=5;U=4 sc2/60 55 . GC 72 PASS N=2 F=5;U=4 sc2/68 20 . TC 71 PASS N=2 F=5;U=4 sc2/10 24 . TG 31 PASS N=2 F=5;U=4 sc2/40 59 . TG 31 PASS N=2 F=5;U=4 sc2/24 24 . AG 38 PASS N=2 F=5;U=4 

Вывод:

 sc2/80 20 . AT 86 PASS N=2 F=5;U=4 sc2/80 20 . AC 80 PASS N=2 F=5;U=4 sc2/60 55 . GT 76 PASS N=2 F=5;U=4 sc2/60 55 . GC 72 PASS N=2 F=5;U=4 

Я новичок в этой области, и я ценю вашу помощь.

Вы можете использовать awk . Поместите в скрипт следующее: script.awk :

 FNR == NR { f1[$1,$2,$4] = $0 f1_c14[$1,$2,$4] = 1 f1_c5[$1,$2,$4] = $5 next } f1_c14[$1,$2,$4] { if ($5 != f1_c5[$1,$2,$4]) print f1[$1,$2,$4]; } f1[$1,$2,$4] { if ($5 != f1_c5[$1,$2,$4]) print $0; } 

Теперь запустите его так:

 $ awk -f script.awk file1 file2 sc2/80 20 . AT 86 PASS N=2 F=5;U=4 sc2/80 20 . AC 80 PASS N=2 F=5;U=4 sc2/60 55 . GT 76 PASS N=2 F=5;U=4 sc2/60 55 . GC 72 PASS N=2 F=5;U=4 

Скрипт работает следующим образом. Этот блок создает 3 массива, f1 , f1_c14 и f1_c5 . f1 содержит все строки file1 в массиве, индексированные с использованием содержимого столбцов 1, 2 и 4 из файла1. f1_c14 – это еще один массив с тем же индексом (содержимое 1, 2 и 4) и значение 1 . 3-й массив использует тот же индекс, что и первый 2, со значением 5-го столбца из файла1.

 FNR == NR { f1[$1,$2,$4] = $0 f1_c14[$1,$2,$4] = 1 f1_c5[$1,$2,$4] = $5 next } 

Следующий блок отвечает за печать строк из 1-го файла, file1 в условиях, когда столбцы 1, 2 и 4 соответствуют столбцам из file2 , и он будет onlu печатать строку из file1 если 5 столбцов file1 и file2 делают не соответствует.

 f1_c14[$1,$2,$4] { if ($5 != f1_c5[$1,$2,$4]) print f1[$1,$2,$4]; } 

Третий блок отвечает за печать связанной строки из file2 , в строке f1 имеется соответствующая строка в столбцах 1, 2 и 4 файла2. Снова она выводится только в том случае, если 5 столбцов не совпадают.

 f1[$1,$2,$4] { if ($5 != f1_c5[$1,$2,$4]) print $0; } 

пример

Выполнение приведенного выше сценария:

 $ awk -f script.awk file1 file2 sc2/80 20 . AT 86 PASS N=2 F=5;U=4 sc2/80 20 . AC 80 PASS N=2 F=5;U=4 sc2/60 55 . GT 76 PASS N=2 F=5;U=4 sc2/60 55 . GC 72 PASS N=2 F=5;U=4 

Вы можете использовать команду column чтобы немного очистить вывод:

 $ awk -f script.awk file1 file2 | column -t sc2/80 20 . AT 86 PASS N=2 F=5;U=4 sc2/80 20 . AC 80 PASS N=2 F=5;U=4 sc2/60 55 . GT 76 PASS N=2 F=5;U=4 sc2/60 55 . GC 72 PASS N=2 F=5;U=4 

Как это работает?

FNR == NR

Это делает использование awk способностью перебирать файлы определенным образом. Здесь мы перебираем файлы, и когда мы находимся на линии, которая находится из первого файла, file , мы хотим запустить конкретный блок кода в этой строке из file1 .

В этом примере показано, что делает FNR == NR , когда мы даем ему 2 имитируемых файла. У одного есть 4 линии, а у другого 5 строк:

 $ awk 'BEGIN {print "NR\tFNR\tline"} {print NR"\t"FNR"\t"$0}' \ <(seq 1 4) <(seq 1 5) NR FNR line 1 1 1 2 2 2 3 3 3 4 4 4 5 1 1 6 2 2 7 3 3 8 4 4 9 5 5 

другие блоки

Остальные блоки, f1_c14[$1,$2,$4] И f1[$1,$2,$4] выполняются только тогда, когда значения из этих элементов массива имеют значение.

Вот решение в Perl. Вы должны сохранить следующий код в файле и запустить его как скрипт (см. Ниже):

 #!/usr/bin/perl $file1 = '/path/to/file1'; $file2 = '/path/to/file2'; open $f1,'<',$file1; open $f2,'<',$file2; while(<$f1>){ ($c1,$c2,$c4,$c5) = (split / /)[0,1,3,4]; #get relevant columns in file 1 $lines_dictionary{"$c1 $c2 $c4"}="$c5---$_"; #create a hash entry keyed by the relevant columns } while(<$f2>){ ($c1,$c2,$c4,$c5) = (split / /)[0,1,3,4]; #get relevant columns in file 2 if(exists $lines_dictionary{"$c1 $c2 $c4"}){ #if a line with similar columns was seen in file 1 ($file1_c5,$file1_line) = split /---/,$lines_dictionary{"$c1 $c2 $c4"}; #parse the hash entry this line in file 1 if($file1_c5 -ne $c5){ #if column 5 of file 2 doesn't match column 5 of file 1 print "${file1_line}$_\n"; #we only need one extra newline as the lines read from the files have trailing ones. } } } close $f1; close $f2; в #!/usr/bin/perl $file1 = '/path/to/file1'; $file2 = '/path/to/file2'; open $f1,'<',$file1; open $f2,'<',$file2; while(<$f1>){ ($c1,$c2,$c4,$c5) = (split / /)[0,1,3,4]; #get relevant columns in file 1 $lines_dictionary{"$c1 $c2 $c4"}="$c5---$_"; #create a hash entry keyed by the relevant columns } while(<$f2>){ ($c1,$c2,$c4,$c5) = (split / /)[0,1,3,4]; #get relevant columns in file 2 if(exists $lines_dictionary{"$c1 $c2 $c4"}){ #if a line with similar columns was seen in file 1 ($file1_c5,$file1_line) = split /---/,$lines_dictionary{"$c1 $c2 $c4"}; #parse the hash entry this line in file 1 if($file1_c5 -ne $c5){ #if column 5 of file 2 doesn't match column 5 of file 1 print "${file1_line}$_\n"; #we only need one extra newline as the lines read from the files have trailing ones. } } } close $f1; close $f2; в #!/usr/bin/perl $file1 = '/path/to/file1'; $file2 = '/path/to/file2'; open $f1,'<',$file1; open $f2,'<',$file2; while(<$f1>){ ($c1,$c2,$c4,$c5) = (split / /)[0,1,3,4]; #get relevant columns in file 1 $lines_dictionary{"$c1 $c2 $c4"}="$c5---$_"; #create a hash entry keyed by the relevant columns } while(<$f2>){ ($c1,$c2,$c4,$c5) = (split / /)[0,1,3,4]; #get relevant columns in file 2 if(exists $lines_dictionary{"$c1 $c2 $c4"}){ #if a line with similar columns was seen in file 1 ($file1_c5,$file1_line) = split /---/,$lines_dictionary{"$c1 $c2 $c4"}; #parse the hash entry this line in file 1 if($file1_c5 -ne $c5){ #if column 5 of file 2 doesn't match column 5 of file 1 print "${file1_line}$_\n"; #we only need one extra newline as the lines read from the files have trailing ones. } } } close $f1; close $f2; 

Используйте любой текстовый редактор, чтобы вставить этот скрипт в файл, изменить переменные $file1 и $file2 чтобы отразить истинные местоположения ваших файлов, а затем сделать исполняемый файл сценария:

 $ chmod +x /path/to/script 

Наконец, вызовите скрипт:

 $ /path/to/script 

отказ

  • Этот код не проверен
  • Этот код предполагает, что шаблон «—» вряд ли встречается в 5-м столбце.
  • Этот код предполагает, что строки в файле 1 уникальны (т. Е. Каждая строка имеет другую комбинацию столбца column1 column2 column4). Если имеется несколько строк (не обязательно последовательных), содержащих одни и те же данные в соответствующих столбцах, сценарий будет использовать последний (самый нижний в файле) этих строк.