У меня есть файл (list_20.txt), который выглядит так:
[{"d_prime":"0.475425","variation1":"rs909776","r2":"0.057940","variation2":"rs16991816","population_name":"1000GENOMES:phase_3:KHV"}]
[{"r2":"0.057940","variation1":"rs909776","d_prime":"0.475425","population_name":"1000GENOMES:phase_3:KHV","variation2":"rs16991819"}]
[{"variation1":"rs909776","r2":"0.078476","d_prime":"0.546491","population_name":"1000GENOMES:phase_3:KHV","variation2":"rs8114269"}]
[{"population_name":"1000GENOMES:phase_3:KHV","variation2":"rs8114269","r2":"0.073418","variation1":"rs6130034","d_prime":"0.528588"}]
[{"population_name":"1000GENOMES:phase_3:KHV","variation2":"rs1201686","r2":"0.060239","variation1":"rs3746539","d_prime":"0.271891"}]
[{"variation2":"rs1201686","population_name":"1000GENOMES:phase_3:KHV","d_prime":"0.280262","r2":"0.058212","variation1":"rs2144011"}]
[{"population_name":"1000GENOMES:phase_3:KHV","variation2":"rs10485662","r2":"0.058826","variation1":"rs844808","d_prime":"0.423639"}]
[{"variation2":"rs6065565","population_name":"1000GENOMES:phase_3:KHV","d_prime":"0.638509","r2":"0.110749","variation1":"rs6139746"}]
[{"r2":"0.110749","variation1":"rs6139746","d_prime":"0.638509","population_name":"1000GENOMES:phase_3:KHV","variation2":"rs6072936"}]
[{"population_name":"1000GENOMES:phase_3:KHV","variation2":"rs6065562","variation1":"rs6139746","r2":"0.091021","d_prime":"0.606214"}]
[{"variation1":"rs6139746","r2":"0.910749","d_prime":"0.638509","population_name":"1000GENOMES:phase_3:KHV","variation2":"rs6072937"}]
...
Я хотел бы для извлечения только строк, которые имеют значение после "r2":" больше 0,7 и меньше или равно 1
в этом примере ожидаемым результатом будет только эта строка:
[{"variation1":"rs6139746","r2":"0.910749","d_prime":"0.638509","population_name":"1000GENOMES:phase_3:KHV","variation2":"rs6072937"}]
Я пробовал это:
awk '$NF >= 0.8 && $NF <1 {print $0}' list_20.txt > 20.out
, но я получил пустой файл. Также эта команда не относится к интересующей строке: "r2":"
awk -F'[][{},]' '{
for (i=3;i<=NF-2;i++){
if ($i ~ /^"r2"/){
r2=substr($i, 7, length($i)-7)
if (r2>0.7 && r2<=1){ print; break }
}
}
}' list_20.txt > 20.out
Используйте ]
, [
, {
, }
и ,
в качестве разделителей полей. Затем перебираем поля в каждой записи, пропуская первые два и последние два поля (, так как они всегда пусты ).
Проверить, начинается ли текущее поле с "r2"
, и извлечь значение с помощью substr($i, 7, length($i)-7)
, т. е. пропустить первые 6 символов "r2":"
и опустить последний символ "
.
Распечатать запись, если значение находится в пределах диапазона, и разорвать цикл.
Неэффективный метод, но моя попытка
sed 's/[\["{}]//g' i.txt| sed 's/\]//g'|sed 's/,/ /g'| awk -F ":" '{for(i=1;i<=NF;i++){if ($i ~ /r2/ && $(i+1) > 0.7) {print $0}}}'| perl -pne "s/ /\n/g"| sed 's/^/"/g'|sed 's/$/"/g'| perl -pne 's/\n/,/g'| sed 's/^/[{/g'| sed 's/$/}]/g'| sed "s/,}]/}]/g"
выход
[{"variation1:rs6139746","r2:0.910749","d_prime:0.638509","population_name:1000GENOMES:phase_3:KHV","variation2:rs6072937"}]
Поскольку это похоже на JSON,давайте воспользуемся парсером JSON командной строки:
$ jq '.[] | select((.r2|tonumber) > 0.7 and (.r2|tonumber) <= 1)' file
{
"variation1": "rs6139746",
"r2": "0.910749",
"d_prime": "0.638509",
"population_name": "1000GENOMES:phase_3:KHV",
"variation2": "rs6072937"
}
Нам нужно преобразовать значения ключей r2
в правильные числа из строк с tonumber
, но кроме этого, это простой фильтр через select()
.
Мы можем несколько сократить его или, по крайней мере, не преобразовывать каждое число дважды с помощью
jq '.[] | (.r2|tonumber) as $r2 | select($r2 > 0.7 and $r2 <= 1)' file
Если вы хотите, чтобы результаты были в том же формате, что и ввод, используйте
$ jq -c '.[] | (.r2|tonumber) as $r2 | select($r2 > 0.7 and $r2 <= 1) | [.]' file
[{"variation1":"rs6139746","r2":"0.910749","d_prime":"0.638509","population_name":"1000GENOMES:phase_3:KHV","variation2":"rs6072937"}]
То есть запросите «компактный вывод» с помощью -c
и создайте массив для каждого результата, извлеченного с помощью фильтра select()
с помощью [.]
.
С Awk:
awk 'match($0, /"r2":"[^"]+"/) {
t = substr($0, RSTART+6, RLENGTH-7)
f = 0.7<t+0 && t+0<=1
if ( f ) print
}' list_20.txt
Это можно сделать и в perl:
perl -lne '
print if /"r2":"(.*?)"/ and 0.7<$1 && $1<=1;
' list_20.txt
Ищем строку r2 в кавычках и то, что следует за ней. Затем применяется условие проверки диапазона, а затем печатается строка, если она находится в пределах диапазона.
При условии, что числа являются числами с плавающей запятой, вы можете выделить строки следующим образом:
$ LC_ALL=C grep -E '"r2":"((0?\.(7[0-9]*[1-9][0-9]*|[89][0-9]*))|1(\.0*)?)"' list_20.txt
-E
опция включает расширенное регулярное выражение