5

I would like to replace everything but my ::ID and [ID2], but could not really find a way to do it with sed and keep to match, any suggestion?

For example:

TRINITY_DN75270_c3_g2::TRINITY_DN75270_c3_g2_i4::g.22702::m.22702 [sample]

I would like to have:

TRINITY_DN75270_c3_g2_i4[sample]

Any suggestion?

4 Answers 4

7

For a given input as provided, this sed expression seems to do what you ask:

$ cat input
`>TRINITY_DN75270_c3_g2::TRINITY_DN75270_c3_g2_i4::g.22702::m.22702 [sample]`
$ sed 's/^.*::\([A-Z_0-9a-z]*\)::.*\[\(.*\)\].*/\1[\2]/' input
TRINITY_DN75270_c3_g2_i4[sample]

The magic is in using regular expression groups, and two backreferences to reconstruct the desired output. To expound:

NODE                     EXPLANATION
--------------------------------------------------------------------------------
  ^                        the beginning of the string
  .*                       any character except \n (0 or more times
                           (matching the most amount possible))
  ::                       '::'
  \(                       group and capture to \1:
    [A-Z_0-9a-z]*            any character of: 'A' to 'Z', '_', '0'
                             to '9', 'a' to 'z' (0 or more times
                             (matching the most amount possible))
  \)                       end of \1
  ::                       '::'
  .*                       any character except \n (0 or more times
                           (matching the most amount possible))
  \[                       '['
  (                        group and capture to \2:
    .*                       any character except \n (0 or more times
                             (matching the most amount possible))
  )                        end of \2
  \]                       ']'
  .*                       any character except \n (0 or more times
                           (matching the most amount possible))

So \1 is the first key you wanted to extract, and \2 is whatever is in the square braces afterward. Is is then reconstructed by \1[\2]/, creating your desired output.

4
  • could be great if you can explain it for beginners :) . I understand how you keep the first part but not the second (i.e [sample])
    – gusa10
    Commented Jun 30, 2017 at 21:05
  • 2
    I have added a detailed piece-by-piece guide to the expression used in the sed command.
    – DopeGhoti
    Commented Jun 30, 2017 at 21:22
  • . DOES match a \n. So you should fix the sentence: .* any char except \n
    – user218374
    Commented Jul 1, 2017 at 11:16
  • . would match \n if it weren't already consumed in the process of splitting the input line by line.
    – DopeGhoti
    Commented Jul 5, 2017 at 15:28
3

awk alternative:

awk -F'::' '{ match($NF,/\[.+\]/); print $2 substr($NF,RSTART,RLENGTH) }' file

The output:

TRINITY_DN75270_c3_g2_i4[sample]

  • -F'::' - considering :: as field separator
1
  • or just awk -F'::| ' '{print $2 $NF}'
    – Sundeep
    Commented Jul 2, 2017 at 15:39
2
sed -e '
   s/::/\n/; s//\n/
   s/.*\n\(.*\)\n.*\(\[[^]]*]\).*/\1\2/
' data

We mark out the ID by replacing the :: occurring 1st & 2nd time. Then we take away anything but the marked region + [...] region

Results:

TRINITY_DN75270_c3_g2_i4[sample]
1

Assuming you would like to keep the second field between the :: separators + [sample], so deleting everything before and after the field till the last space you could:

sed 's/^[^:]*::\([^:]*\)::.* /\1/'  

This will match from the beginning of the line till the last following space (.* is "greedy"), and replace it just with the first "sub-expression" (marked with escaped brackets).

For more details on backreferences and sub-expressions see this description on gnu.org.

1
  • When using the extended-regex mode sed -r, the brackets don't need to be escaped.
    – ZleekWolf
    Commented Jun 30, 2017 at 20:21

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .