5
Staphylococcus_sp_HMSC14C01-KV792037.1:0.00371647154267842634,Staphylococcus_hominis_VCU122-AHLD01000058.1:0.00124439639436691308)69:0.00227646100249620856,(Staphylococcus_sp_HMSC072E01-KV814990.1:0.00288325234399461859,(((Staphylococcus_hominis_793_SHAE-JUSR01000051.1:0.00594391769091206796,Staphylococcus_pettenkoferi_1286_SHAE-JVVL01000037.1:0.00594050248317441135)

The comma is separating different items and in each item I want to remove everything between - and : including - but keeping :.

How can I do that? So it should look like:

Staphylococcus_sp_HMSC14C01:0.00371647154267842634,Staphylococcus_hominis_VCU122:0.00124439639436691308)69:0.00227646100249620856

I used sed 's/-.*://' 1.file > 2.file but ended up removing the whole file and just kept the first and last values.

1
  • 1
    It looks like your input is a single line, and sed operates a line at a time. Since your regular expression allows for matching .*, the longest (greedy) match is from the first - to the last :. That's why it's deleting everything. You could try replacing the .* with [^,]*, which will force it to stop at the comma between items.
    – Dave M.
    Sep 29, 2017 at 20:51

2 Answers 2

7

.* is a greedy regexp, matching the longest possible match. You need to match the shortest match but match it globally on the whole line. Try

sed 's/-[^:-]*:/:/g' 1.file > 2.file

The character class [^:-] matches anything except colon and dash (and maybe it should match anything except colon only), so the regexp says "dash followed by any number of non-dash, non-colon characters followed by a colon". It then replaces that with a colon (since you wanted to keep that) and does the replacement globally (the trailing g) on the line. If you omit the g, only the first instance would be replaced.

3
  • Thanks Nick, I still do not understand why cannot we say directly sed 's/-*:/:/g' why do we need [^:-]? Sep 29, 2017 at 21:26
  • .* will match the longest sequence of characters possible (that's why it's termed "greedy"). So /-.*:/ says "dash followed by any number of characters followed by colon": that matches the first dash and the last colon in your line (and everything in between) because that's longer than any other match. Is that clear?
    – NickD
    Sep 29, 2017 at 21:30
  • Thank you so much! I've tweaked your regex to help me convert a JSON localization file to an iOS localization file. This was so helpful.
    – Felipe
    Mar 19, 2021 at 16:47
4

Awk solution:

awk -F',' '{ for(i=1;i<=NF;i++) sub(/-[^:-]+/,"",$i) }1' OFS=',' 1.file

  • -F',' - field separator

  • for(i=1;i<=NF;i++) - iterating through all fields of the record

  • sub(/-[^:-]+/,"",$i - substitute the needed sequence (between - and : including - but keeping :)


The output:

Staphylococcus_sp_HMSC14C01:0.00371647154267842634,Staphylococcus_hominis_VCU122:0.00124439639436691308)69:0.00227646100249620856,(Staphylococcus_sp_HMSC072E01:0.00288325234399461859,(((Staphylococcus_hominis_793_SHAE:0.00594391769091206796,Staphylococcus_pettenkoferi_1286_SHAE:0.00594050248317441135)
2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.