1

I am trying to implement sed replace with shell variables. As far for now I have working sed replace with '

sed -i -r 's#(export\ PATH=")(.*)#\1/home/USER/bin:~/.local/bin:\2#' ~/.zshrc

But unfortunately ' does not expand shell variables just as stated in this answer https://stackoverflow.com/a/5156322/675100

While trying to use " I keep getting problems with parentheses etc. I would like to make this generic to always use whoami instead of USER

The first attempt would be

sed -i -r "s#\(export\ PATH=\"\)(.*)#\1/home/`whoami`/bin:~/.local/bin:\2#" ~/.zshrc
sed: -e expression #1, char 60: invalid reference \2 on `s' command's RHS

EDIT

I have tried

sed -i -r "s#\(export\ PATH=\"\)\(.*\)#\1/home/$(whoami)/bin:~/.local/bin:\2#" ~/.zshrc

to escape the second group but I get the similar error :

sed: -e expression #1, char 63: invalid reference \2 on `s' command's RHS
Community
  • 1
  • 1
Patryk
  • 22,602
  • 44
  • 128
  • 244
  • Note that only `$` and back-ticks cause troubles inside double quotes; parentheses are only relevant when preceded by `$` as in `$(whoami)`, etc. – Jonathan Leffler Dec 20 '13 at 17:08
  • You escaped the first pair of parentheses, but not the second pair around `(.*)`. That's why there is no second group that can be referenced with `\2`. Also, what's `-r` for? My copy of `sed` doesn't have that one… – svckr Dec 20 '13 at 17:19
  • why are you specifically using `/home/USER/bin` instead of `~/bin`? – glenn jackman Dec 20 '13 at 17:59
  • @glennjackman I have tried that but zsh wouldn't recognize that correctly - I have no idea why. – Patryk Dec 20 '13 at 18:00

3 Answers3

3

You can write like this:

sed -i 's#export PATH="#&/home/'$(whoami)'/bin:~/.local/bin:#' ~/.zshrc

Or as @glennjackman pointed out:

sed -i 's#export PATH="#&~/bin:~/.local/bin:#' ~/.zshrc

Notice that:

  • Instead of matching (start)(end) and inserting between like (start)"newstuff"(end), you can match just (start), replace it with itself using & and insert your "newstuff"
  • To simplify the quoting, you can end the single-quoted part anytime and start a new single-quoted part later, because these are equivalent:

    echo 'hello there'
    echo 'hello'' there'
    
janos
  • 120,954
  • 29
  • 226
  • 236
1

backslash escapes are preformed within double-quotes strings, so you have to escape all the backslashes!

sed -i -r "s#\\(export PATH=\"\\)\\(.*\\)#\\1/home/$(whoami)/bin:~/.local/bin:\\2#" ~/.zshrc

I'd use one of the following to determine the user's home dir.

sed -i -r "s#\\(export PATH=\"\\)\\(.*\\)#\1~/bin:~/.local/bin:\\2#" ~/.zshrc
sed -i -r "s#\\(export PATH=\"\\)\\(.*\\)#\1$HOME/bin:~/.local/bin:\\2#" ~/.zshrc
sed -i -r "s#\\(export PATH=\"\\)\\(.*\\)#\1$(getent passwd $LOGNAME | cut -d: -f6)/bin:~/.local/bin:\\2#" ~/.zshrc

Your whole approach looks fragile.

  • What if, since the PATH is already exported, I use PATH="..." ?
  • What if I use single quotes?
  • What if I use a different dot file?

Why don't you just use

PATH="~/bin:~/.local/bin:$PATH"

??

glenn jackman
  • 238,783
  • 38
  • 220
  • 352
0

Ok so the problem was with the -r flag which used extended regular expressions.

The final solution was to use :

sed -i "s#\(export\ PATH=\"\)\(.*\)#\1/home/$(whoami)/bin:~/\.local/bin:\2#" ~/.zshrc 
Patryk
  • 22,602
  • 44
  • 128
  • 244