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 ? Commented Jun 28, 2017 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
    Commented Jun 29, 2017 at 2:06

3 Answers 3

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.

You must log in to answer this question.

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