#unix #awk
#unix #awk
Вопрос:
У меня есть два файла для сравнения. Я нашел, как сравнивать столбцы и печатать в соответствии с условием. Моя проблема заключается в том, что я должен проверить, находится ли значение столбца [2] в file1 между значением в file2, определенным как диапазон в двух столбцах, col [2] col[3]. Если это верно, то я должен напечатать столбец [4] файла 2 в моем file1.
файл1:
scaffold1_size11 12
scaffold2_size22 26
scaffold3_size33 67
файл2:
scaffold1_size11 1 10 Os01
scaffold1_size11 12 20 Os08
scaffold1_size11 29 59 Os07
scaffold2_size22 17 24 Os09
scaffold2_size22 27 38 Os09
scaffold2_size22 39 60 Os10
scaffold2_size22 67 78 Os10
scaffold3_size33 15 27 Os03
scaffold3_size33 29 62 Os08
scaffold3_size33 64 78 Os02
scaffold3_size33 80 98 Os01
желаемый результат:
scaffold1_size11 12 Os08
scaffold2_size22 26
scaffold3_size33 67 Os02
Как это должно быть сделано?
Комментарии:
1. «я должен напечатать столбец [2] файла 2 в моем file1». Неясно; пожалуйста, укажите желаемый результат для этого конкретного примера.
2. я рассмотрел свой вопрос с желаемым результатом.
3. Пожалуйста, проверьте желаемый результат для
scaffold2_size22
; там должно быть третье значение (ofOs09
).
Ответ №1:
Вот сценарий оболочки, который делает то, что вы хотите. Он использует awk для преобразования file2 в другой скрипт awk (tmp.awk), который, в свою очередь, фильтрует file1.
awk '{ a[$1] = a[$1] "$2 >= " $2 " amp;amp; $2 <= " $3 " ? "" $4 "" : "; } END { for (i in a) print "$1 == "" i "" { print $0 "\t" (" a[i] """); }"; }' file2 > tmp.awk
awk -f tmp.awk file1
Примечания:
- Повторяющиеся строки в file1 приводят к дублированию строк в выходных данных. При необходимости передайте результат в
uniq
илиsort -u
. - Этот подход основан на предположении, что обычно файл2 будет относительно небольшим (по сравнению с потенциально большим файлом1); если нет, то этот подход может привести к снижению производительности.
Ответ №2:
В Unix есть стандартная идиома, awk
которая использует FNR
(номер записи файла) и NR
(общий номер записи) для определения того, когда вы читаете первый файл. Вы считываете и сохраняете значения первого файла в массивах, а затем используете массивы при чтении второго файла.
В этом контексте вы хотите сначала прочитать file1
, сохранив записи на основе значения в столбце 1 ( $1
). Это предполагает, что ключи в file1
(первом поле) уникальны. Затем, при чтении второго файла,
awk 'FNR == NR { val[$1] = $2 }
FNR != NR { if ($1 in val amp;amp; val[$1] >= $2 amp;amp; val[$1] <= $3)
print $1, val[$1], $4
}' file1 file2
Пример вывода:
scaffold1_size11 12 Os08
scaffold2_size22 26 Os09
scaffold3_size33 67 Os02
Обратите внимание, что это отличается от примера вывода в вопросе, который:
scaffold1_size11 12 Os08
scaffold2_size22 26
scaffold3_size33 67 Os02
Я предполагаю, что это опечатка в вопросе, поскольку ни в одной из строк в file2
отсутствует четвертый столбец.
Вы также увидите идиому, используемую как:
awk 'FNR == NR { …save…; next }
{ …process… }'
next
Пропускает второй блок кода при чтении первого файла. Это могло бы быть немного эффективнее, но мне, как правило, нравится явная ясность двух инвертированных условий.
Если интервал в выходных данных является проблемой, используйте соответствующий printf
оператор вместо print
.
Комментарии:
1. да, есть опечатка. На самом деле, также существует ситуация, при которой присвоение любой ОС file1 остается пустым. Чтобы включить это условие, я также выдал это в качестве желаемого результата.
2. Вы не дали никаких указаний о том, как возникает это особое условие. Это делает плохой идеей включение его в ожидаемый результат. Либо точно объясните, что вы хотите, включая морщины, либо покажите простой вывод, игнорирующий морщины, с которыми вы можете (и должны) иметь дело после того, как у вас будет базовый механизм на месте.
3. извините за ошибку при вводе, теперь я включил это условие также в свой вопрос.