возможно, на мой вопрос следует ответить двумя способами, но я надеюсь, что это можно сделать с помощью одного "sed":
У меня есть следующие строки с разными идентификаторами:
ID1_TRINITY_DN120587_c0_g1 :: TRINITY_DN120587_c0_g1_i1 :: g.8298 :: m.8298
и я хотел бы получить:
TRINITY_DN120587_c0_g1_i1 [ID1]
sed -e '
s/::/\n/;s//\n/
s/^\([^_]*\)_.*\n\(.*\)\n.*/\2[\1]/
;# |--1---| |-2-|
' ID.data
Поместите маркеры вокруг строки идентификатора и захватите часть перед первой _и замените всю строку этими значениями. Выход:
TRINITY_DN120587_c0_g1_i1[ID1]
ID1_TRINITY_DN120587_c0_g1::TRINITY_DN120587_c0_g1_i1::g.8298::m.8298
|-| |-----------------------|
Вы сказали, что хотите извлечь идентификатор, который находится между 1-м и 2-м вхождением::
Шаг -1 :Поместите маркер (обычно \n )вокруг интересующей области:
s/::/\n/;s//\n/
This is how the pattern space looks after the above tranformation
ID1_TRINITY_DN120587_c0_g1\nTRINITY_DN120587_c0_g1_i1\ng.8298::m.8298
Шаг -2 :Извлеките идентификатор, который находится между двумя \ns, а также строку для слева от 1-го вхождения_
s/^\([^_]*\)_.*\n\(.*\)\n.*/\2[\1]/
;# |------| |---|
;# \1 \2
[^_] => matches any char but an underscore
[^_]* => matches 0 or more non underscore char(s)
\([^_]*\) => store what was matched into a memory, recallable as \1
^\([^_]*\) => anchor your matching from the start of the string
.*\n => go upto to the rightmost \n you can see in the string
\n\(.*\)\n => Ooops!! we see another \n, hence we need to backtrack to
the previous \n position and from there start moving right again
and stop at the rightmost \n. Whatever is between these positions
is the string ID and is recallable as \2. Since the \ns fall outside
the \(...\), hence they wouldn't be stored in \2.
.* => This is a catchall that we stroll to the end of the string after
starting from the rightmost \n position and do nothing with it.
So our regex engine has matched against the input string it was given in
the pattern space and was able to store in two memory locations the data
it was able to gather, viz.: \1 => stores the string portion which is in
between the beginning of the pattern space and the 1st occurrence of the
underscore.
\2 => store the string portion which is in between the 1st and 2nd
occurrences of :: in the pattern space.
\1 = ID1
\2 = TRINITY_DN120587_c0_g1_i1
Now comes the replacement part. Remember that the regex engine was able to scan
the whole of pattern space from beginning till end, hence the replacement
will effect the whole of the pattern space.
\2[\1] => We replace the matched portion of the pattern space (in our case it
happens to be the entire string) with what has been stored in
the memory \2 literal [ memory \1 literal ]
leading to what we see below:
TRINITY_DN120587_c0_g1_i1[ID1]
In other words, you have just managed to turn the pattern space from:
ID1_TRINITY_DN120587_c0_g1::TRINITY_DN120587_c0_g1_i1::g.8298::m.8298
into the following:
TRINITY_DN120587_c0_g1_i1[ID1]
Я предполагаю, что ваш шаблон останется прежним, это единственное sed
решение должно работать.
sed -n "s/^\([^_]*\)_[^:]*::\([^:]*\)::.*/\2\[\1\]/p" filename
Выход для примера ввода:
TRINITY_DN120587_c0_g1_i1[ID1]
Пояснение :Начните с начала строки, сопоставьте содержимое до первого знака подчеркивания [^_]*
и сохраните его в первой группе, затем сопоставьте вторую группу между первым и вторым двойным двоеточием [^:]*
. Замените эту строку и сопоставьте с желаемым выходным форматом, p напечатает измененную строку.
awkрешение:
awk -F'::' '{ print $2"[" substr($1,1,index($1,"_")-1) "]"}' file
Выход:
TRINITY_DN120587_c0_g1_i1[ID1]
-F'::'
-разделитель поля
substr($1,1,index($1,"_")-1)
-извлечение подстроки из 1-го поля, начиная с 1-й позиции до первого появления _
(, т.е.ID1
)