Извлечение информации из строки с определенным шаблоном с использованием awk / sed - PullRequest
1 голос
/ 27 марта 2019

У меня есть такой файл, т.е.

A   10  20  bob.1   ID=bob.1;Parent=bob;conf=XF;Note=bob_v1
A   20  30  bob.2   ID=bob.2;Parent=bob;Note=bob_v1;conf=XF

Используя командную строку ниже, я извлекаю информацию в виде отдельного столбца для conf.

sed -Ei 's/(.*conf=)([^;]*)(;.*)/\1\2\3\t\2/g' my_file

Однако, если в конце conf есть этот символ; оно работает. В противном случае нет. Как изменить скрипт для извлечения шаблона в обоих случаях, например, и в случае, если вкладка пуста?

A   10  20  bob.1   ID=bob.1;Parent=bob;conf=XF;Note=bob_v1  XF
A   20  30  bob.2   ID=bob.2;Parent=bob;Note=bob_v1;conf=XF  XF

Я использовал эту ссылку в качестве ссылки: https://unix.stackexchange.com/questions/414082/extract-part-of-lines-with-specific-pattern-and-store-in-a-new-field-using-awk-o?noredirect=1&lq=1

Ответы [ 6 ]

1 голос
/ 01 апреля 2019

Более или менее прямая копия моего ответа на вопрос, связанный с этим вопросом:

BEGIN { OFS = FS = "\t" }

function get_attrib_by_name(key,  n,attrib,kv) {
    # Split the attribute field on semi-colons.
    n = split($5, attrib, ";")

    # Loop over the attributes and split each on "=".
    # When we've found the one we're looking for (by key name in "key"),
    # return the corresponding value.
    for (i = 1; i <= n; ++i) {
        split(attrib[i], kv, "=")
        if (kv[1] == key) {
            return kv[2]
        }
    }
}

# Using the above function.
{
    name = get_attrib_by_name("conf")
    print $0, name
}

Тестирование:

$ awk -f script.awk file.gff
A       10      20      bob.1   ID=bob.1;Parent=bob;conf=XF;Note=bob_v1 XF
A       20      30      bob.2   ID=bob.2;Parent=bob;Note=bob_v1;conf=XF XF
1 голос
/ 01 апреля 2019

Нам не нужно требовать ; в \3 - так как он уже обработан в списке символов исключения в \2:

sed -Ei 's/(.*conf=)([^;]*)(.*)/\1\2\3\t\2/' my_file

Если нам нужно бороться с каким-либо другим символомчем ; в качестве разделителя, мы включаем его в список символов в \2.Такой символ может быть \t или пробел?

sed -Ei 's/(.*conf=)([^;\t ]*)(.*)/\1\2\3\t\2/' my_file
1 голос
/ 27 марта 2019

Вы можете попробовать Perl однострочное

$ perl -lne ' /conf=(\w+)/ and $_.=" $1"; print ' conf.txt
A   10  20  bob.1   ID=bob.1;Parent=bob;conf=XF;Note=bob_v1 XF
A   20  30  bob.2   ID=bob.2;Parent=bob;Note=bob_v1;conf=XF XF
$

или даже короче

$ perl -lne ' /conf=(\w+)/ and print "$_ $1" ' conf.txt
A   10  20  bob.1   ID=bob.1;Parent=bob;conf=XF;Note=bob_v1 XF
A   20  30  bob.2   ID=bob.2;Parent=bob;Note=bob_v1;conf=XF XF
1 голос
/ 27 марта 2019

Всякий раз, когда у вас есть входные данные name = value, я нахожу наиболее простым, надежным, наиболее гибким и т. Д. Создать массив, представляющий эту связь (f[name]=value ниже), чтобы вы могли затем просто получить доступ к значениям по их именам.В зависимости от того, что означает in case it is empty to put tab:

$ awk -F'[[:space:];=]+' -v OFS='\t' '
    {delete f; for (i=5; i<NF; i+=2) f[$i]=$(i+1); print $0, f["conf"]}
' file
A   10  20  bob.1   ID=bob.1;Parent=bob;conf=XF;Note=bob_v1     XF
A   20  30  bob.2   ID=bob.2;Parent=bob;Note=bob_v1;conf=XF     XF

или:

$ awk -F'[[:space:];=]+' '
    {delete f; f["conf"]="\t"; for (i=5; i<NF; i+=2) f[$i]=$(i+1); print $0, f["conf"]}
' file
A   10  20  bob.1   ID=bob.1;Parent=bob;conf=XF;Note=bob_v1 XF
A   20  30  bob.2   ID=bob.2;Parent=bob;Note=bob_v1;conf=XF XF
1 голос
/ 27 марта 2019

Не могли бы вы попробовать выполнить следующие действия в awk.

awk 'match($0,/conf=[^;]*/){print $0,substr($0,RSTART+5,RLENGTH-5);next} 1' Input_file

Объяснение: Добавление пояснения к приведенному выше коду сейчас.

awk '                                        ##Starting awk program here.
match($0,/conf=[^;]*/){                      ##Using match function of awk to match regex from string conf= till semi colon comes.
   print $0,substr($0,RSTART+5,RLENGTH-5)    ##Printing current line and then sub-string whose starting point of RSTART+5 and ending point is RLENGTH-5
   next                                      ##next will skip all further statements from here.
}                                            ##Closing BLOCK for match function here.
1                                            ##Mentioning 1 will print lines, those ones which are not having conf string match so it will simply print them.
'  Input_file                                ##Mentioning Input_file name here.

Вывод будет следующим.

A   10  20  bob.1   ID=bob.1;Parent=bob;conf=XF;Note=bob_v1 XF
A   20  30  bob.2   ID=bob.2;Parent=bob;Note=bob_v1;conf=XF XF
1 голос
/ 27 марта 2019

На самом деле вы можете удалить ;:

sed -iE 's/(.*conf=)([^;]*)(.*)/\1\2\3\t\2/g'  my_file

[^;]* - это выражение с отрицанием в скобках, оно будет соответствовать только 0 или более (из-за *) символов, отличных от ;и, таким образом, ; необязательно присутствовать в самом шаблоне, предыдущий шаблон уже «ограничен».

См. online sed demo :

s="A   10  20  bob.1   ID=bob.1;Parent=bob;conf=XF;Note=bob_v1
A   20  30  bob.2   ID=bob.2;Parent=bob;Note=bob_v1;conf=XF"
sed -E 's/(.*conf=)([^;]*)(.*)/\1\2\3\t\2/g' <<< "$s"

Вывод:

A   10  20  bob.1   ID=bob.1;Parent=bob;conf=XF;Note=bob_v1 XF
A   20  30  bob.2   ID=bob.2;Parent=bob;Note=bob_v1;conf=XF XF
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...