У меня есть текстовый файл с разделителями табуляции, содержащий Column1...Columnn столбцов и строки от R1 до Rn . В некоторых столбцах есть несколько вложенных полей с идентификатором, которые затем разделяются точкой с запятой (показано в прилагаемом образце файла изображения красным цветом). Чтобы быть точным, я прилагаю образец снимка файла.

Здесь данные в столбце 6 INFO имеют несколько вложенных полей, таких как DP; RPB; AF1; AC1; DP4;... и т.д.

Задача: В inputfile.txt в столбце 6 INFO выбрать поле DP4=a,b,c,d и выполнить простые арифметические операции над значениями DP4=a,b,c,d(отмечены красным на изображении), например (c+d)/(a+b+c+d) ->, и вставьте результаты для каждой строки как новый столбец INFOextra в тот же файл.

Как это можно сделать на сценарии оболочки e Unix?

1 ответ1

0
awk '$1=="ID" {print $0 "\tINFOextra"; next}; NF { info=$6; gsub(/.*;DP4=|;MQ=.*/, "", info); split(info, a, /,/); print $0 "\t" (a[3]+a[4])/(a[1]+a[2]+a[3]+a[4])}' inputfile.txt > outputfile.txt
# then check the content outputfile.txt and rename it if important

Как видите, решение очень похоже на ответ на ваш предыдущий вопрос, и совсем не дольше. Это потому, что awk очень хорошо настроен для решения таких проблем, как ваша. Я рекомендую взглянуть на его страницу руководства (http://linux.die.net/man/1/awk), чтобы увидеть, насколько она проста по сравнению с другими (и более универсальными) языками.

Если несколько входных файлов должны быть обработаны в несколько выходных файлов с соответствующими именами, параметры следующие:

  • создать цикл в оболочке и запустить процесс awk для каждого файла, один за другим
  • make awk записывает вывод в файлы, имена которых зависят от имени текущего входного файла, информация о котором хранится в переменной FILENAME awk, которая автоматически устанавливается во время процесса. Внутри перенаправления кода awk может использоваться тот же синтаксис и тот же результат, что и в оболочке:

    awk '$ 1 == "ID" {print $ 0 "\tINFOextra"> FILENAME ".out"; следующий}; NF {info = $ 6; GSUB (/.*; DP4 = |; MQ =. */, "", Info); split (информация, а, /, /); выведите $ 0 "\t" (a [3]+a [4]) /(a [1]+a [2]+a [3]+a [4])> FILENAME ".out"} 'inputfile1.txt inputfile2.txt

Здесь каждый экземпляр inputfileN.txt будет иметь соответствующий файл inputfileN.txt.out. FILENAME - простая строка, поэтому любые манипуляции с выходными файлами допустимы.

Когда спецификация усложняется так, что дополнительное поле должно появиться во внутренней позиции (не в начале или в конце), следует создать подпрограмму (называемую функцией в awk) для создания выходных строк. Эта функция перебирает все поля, печатает их как обычно, но там, где должно появиться дополнительное поле, она записывает это после n-го 1-го и перед n-м полем, делая его n-ным. Теперь стоит поместить код awk в отдельный файл:

$ cat bio.awk


function myprint( str) {
   for (i=1; i<=NF; ++i) {
      printf "%s", $i  > FILENAME ".out"
      if (i==44)
         printf "\t%s", str  >> FILENAME ".out"
      if (i!=NF)
         printf "\t"  >> FILENAME ".out"
   }
   print ""  >> FILENAME ".out"
}

$1=="ID" {
   myprint( "INFOextra")
   next
}

NF {
   info=$6
   gsub(/.*;DP4=|;MQ=.*/, "", info)
   split(info, a, /,/)
   myprint( (a[3]+a[4])/(a[1]+a[2]+a[3]+a[4]) )
}

Вызов этого приведет к более короткой и чистой командной строке:

awk -f bio.awk inputfile1.txt inputfile2.txt

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .