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
4
  • Note that only $ and back-ticks cause troubles inside double quotes; parentheses are only relevant when preceded by $ as in $(whoami), etc. Commented Dec 20, 2013 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… Commented Dec 20, 2013 at 17:19
  • why are you specifically using /home/USER/bin instead of ~/bin? Commented Dec 20, 2013 at 17:59
  • @glennjackman I have tried that but zsh wouldn't recognize that correctly - I have no idea why. Commented Dec 20, 2013 at 18:00

3 Answers 3

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'
    
Sign up to request clarification or add additional context in comments.

Comments

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"

??

Comments

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 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.