#linux #comparison #awk #wc
#linux #сравнение #awk #wc
Вопрос:
Я хочу сравнить 3 файла вместе, чтобы увидеть, какая часть информации в файлах одинакова. Формат файла примерно такой:
Chr11 447 . A C 74 . DP=22;AF1=1;CI95=1,1;DP4=0,0,9,8;MQ=15;FQ=-78 GT:PL:GQ 1/1:107,51,0:99
Chr10 449 . G C 35 . DP=26;AF1=0.5;CI95=0.5,0.5;DP4=5,0,7,8;MQ=20;FQ=11.3;PV4=0.055,0.0083,0.028,1 GT:PL:GQ 0/1:65,0,38:41
Chr12 517 . G A 222 . DP=122;AF1=1;CI95=1,1;DP4=0,0,77,40;MQ=23;FQ=-282 GT:PL:GQ 1/1:255,255,0:99
Chr10 761 . G A 41 . DP=93;AF1=0.5;CI95=0.5,0.5;DP4=11,34,6,35;MQ=19;FQ=44;PV4=0.29,1.8e-35,1,1 GT:PL:GQ 0/1:71,0,116:74
Меня интересуют только первые два столбца (если первые два столбца совпадают, то я считаю их равными). Это команда, которую я использую для сравнения двух файлов :
awk 'FILENAME==ARGV[1] {pair[$1 " " $2]; next} ($1 " " $2 in pair)' file1 file2 | wc -l
Я хотел бы использовать команду awk, так как мои файлы действительно большие, и awk обрабатывает их действительно хорошо! но я не мог понять, как использовать его для 3 файлов!
Комментарии:
1. Как бы вы хотели представить общие строки? Распечатайте их все? или просто распечатать первые 2 столбца?
2. все было бы намного лучше!
3. итак, для записи, в которой первые 2 столбца одинаковы, но другие столбцы отличаются в каждом файле, вы хотите, чтобы были напечатаны все 3 строки?
4. кроме того, для каждого файла можно с уверенностью предположить, что пара column1-column2 уникальна?
5. дело в том, что мне это нужно для двух целей, сначала я хочу знать, сколько из них похоже! так что не имеет значения, будут ли использоваться только первые два столбца! но для второй цели я хотел бы иметь всю информацию, если это возможно, в одной строке (все три строки будут напечатаны в одной строке или что-то в этом роде), чего я не хочу, так это иметь 3 строки для одной позиции!
Ответ №1:
Не предназначено для начала войны редакторов, но я знаком с VI, а vimdiff и его варианты показывают сравнение между несколькими файлами в параллельном представлении, что я нахожу очень удобным. Просто вы можете вызвать его с помощью
$ vimdiff <filelist>
Ответ №2:
Если просто распечатать пары (column1 column2), которые являются общими для всех 3 файлов, и использовать тот факт, что пара уникальна в файле, вы могли бы сделать это таким образом:
awk '{print $1" "$2}' a b c | sort | uniq -c | awk '{if ($1==3){print $2" "$3}}'
Это можно сделать с произвольным количеством файлов, если вы измените параметр последней команды.
Вот что он делает:
- печатает и сортирует первые 2 столбца всех файлов (
awk '{print $1" "$2}' a b c | sort
) - подсчитайте количество повторяющихся записей (
uniq -c
) - если количество повторяющихся записей == количество файлов, мы нашли совпадение. распечатайте его.
Если вы делаете это часто, вы можете выразить это как функцию bash (и добавить ее в свой .bashrc
), которая параметризует количество файлов.
function common_pairs {
awk '{print $1" "$2}' $@ | sort | uniq -c | awk -v numf=$# '{if ($1==numf){print $2" "$3}}';
}
Вызовите его с любым количеством файлов, которые вы хотите: common_pairs file1 file2 file3 fileN
Ответ №3:
Для этого я бы использовал команды cut, sort и comm .
- С помощью cut срежьте ненужные поля.
- отсортируйте результат, поскольку comm ожидает отсортированных входных данных.
- Используйте comm, чтобы получить строки, которые находятся в file1 и file2.
- Снова используйте comm, чтобы получить строки, которые также находятся в file3.
Сценарий может выглядеть следующим образом:
for i in 1 2 3
do
# options to cut may have to be adjusted for your input files
cut -c1-15 file$i | sort > tmp.$i
done
comm -12 tmp.1 tmp.2 > tmp.1 2
comm -12 tmp.3 tmp.1 2 > tmp.1 2 3
(Конечно, можно использовать расширенный синтаксис оболочки, чтобы избежать временных файлов, но я не хочу скрывать идею, стоящую за сложными синтаксическими выражениями)
Теперь в файле tmp.1 2 3
у вас должны быть ключи, присутствующие во всех трех файлах. Если вас интересуют целые строки, вы можете использовать команду join в сочетании с отсортированной версией любого из трех входных файлов)
Комментарии:
1. Это также может быть выражено как
comm -12 <(awk '{print $1" "$2}' a|sort) <(awk '{print $1" "$2}' b|sort) | comm -12 - <(awk '{print $1" "$2}' c|sort)
2. Да, но утомительно разбирать для новичка — вот почему я не использовал этот синтаксис
Ответ №4:
Просто прочитайте ваш последний комментарий — вы хотите, чтобы файлы были объединены, но дубликаты удалены?
sort file1 file2 file3 | uniq > newfile
Комментарии:
1. Или просто
sort -u file1 file2 file3
, но я считаю, что это не то, о чем просит OP.