Как проверить, что значение столбца находится между значениями двух столбцов в другом файле, и вывести соответствующее значение из столбца в Unix?

#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 ; там должно быть третье значение (of Os09 ).

Ответ №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. извините за ошибку при вводе, теперь я включил это условие также в свой вопрос.