I am using sed to look for and replace a pattern.

My pattern is "-"

I have the following data

>1-2-3-4-5 29238232382083e-9  
>1-2-3-4-5    29238232382083e-9   
>1-2-3-4-5    29238232382083e-9   
>1-2-3-4-5    29238232382083e-9     

I want to replace the "-" in 1-2-3-4-5 by an "*" so I can get 1*2*3*4*5

However, when I do the replacement with
sed -i -e '/-/*/g

all of the "-" are affected even the 29238232382083e-9 that turn out to 29238232382083e*9.

What could I do to replace all the "-", excepting the "-" that are located after "e" like in this case 29238232382083e-9 ?

  • 1
    Is your real data actually different ? If so how do you know which dashes have to be replaced ? The first four ? All but the last one ? – don_crissti Jun 28 '17 at 23:08
  • yeah, you need to give more detail on input... if you treat space as delimiter and want to replace - only in first column, awk would be better choice.. awk '{gsub("-","*",$1); print}' – Sundeep Jun 29 '17 at 2:06
sed 's/\([^e]\)-/\1*/g' /path/to/input

To elaborate on the sed statement:

  • \([^e]\)- Here we use a grouping to look for any character other than an e followed by a hyphen
  • \1* - Here we replace what was found with whatever was in that grouping (i. g. the non-e that preceded the hyphen), followed by the asterisk that is replacing that hyphen.

Note that this will not work on hyphens that are the first character of a line; for that we'll have to add a special case:

sed 's/\([^e]\)-/\1*/g;s/^-/*/' /path/to/input

This is similar, but replaces a hyphen that is the first character of the line with an asterisk. Since it's the first character, it cannot be preceded by an e.


Choose one:

awk approach:

awk '{ gsub("-","*",$1) }1' OFS='\t' file
  • gsub("-","*",$1) - replace all - with * within the 1st field

perl approach:

perl -lae '$,="\t"; $F[0] =~ y/-/*/; print @F' file
  • -a - auto-split $_ into the array @F

  • $,="\t" - join fields with \t (tab)

  • $F[0] =~ y/-/*/ - translate all - to * within the 1st field $F[0]

The output (for both awk and perl approaches):

>1*2*3*4*5  29238232382083e-9
>1*2*3*4*5  29238232382083e-9
>1*2*3*4*5  29238232382083e-9
>1*2*3*4*5  29238232382083e-9

sed approach:

sed 'h; s/ .*$//; y/-/*/;G; s/\n[^[:space:]]*//' file

The output (for sed approach):

>1*2*3*4*5 29238232382083e-9  
>1*2*3*4*5    29238232382083e-9   
>1*2*3*4*5    29238232382083e-9   
>1*2*3*4*5    29238232382083e-9

Though it can be done with POSIX sed, but here it's shown using GNU sed owing to simple expressions:

sed -e '
' yourfile


>1*2*3*4*5 29238232382083e*9
>1*2*3*4*5    29238232382083e*9
>1*2*3*4*5    29238232382083e*9
>1*2*3*4*5    29238232382083e*9


  • Mark the boundary where we want the changes to happen.
  • Then we setup a loop and perform the change in it progressively.

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.