3

I am trying to replace a line in file and am running in to issues.

Original File:

export PS1='\h:\w\$ '

Command I am running:

perl -pi -e 's~PS1.*~PS1="\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]~g' ~/.bashrc

Error message:

syntax error at -e line 1, near "e["
Execution of -e aborted due to compilation errors.

I also tried sed:

sed -i 's~PS1.*~PS1="\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]~g' ~/.bashrc

Result with Sed:

export PS1="
[e[32;1m][[e[37;1m]@h:[e[37;1m]w[e[32;1m]]\$ [e[0m]

Expected Result File:

export PS1="\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]"

End Result

This doesn't have much to do with the question except to show folks what the PS1 will look like when working properly

enter image description here

brakertech
  • 1,467
  • 1
  • 13
  • 20
  • Thanks for including clear instructions for reproducing, as well as expected and actual results! You should also take some time to try to narrow the problem down. For example, this problem is not specific to PS1, and a MCVE could be "Why does `echo "foobar" | sed 's/foo/\n/'` output a linefeed+bar instead of `\nbar`?" See [How much research effort is expected of Stack Overflow users?](https://meta.stackoverflow.com/questions/261592/how-much-research-effort-is-expected-of-stack-overflow-users) – that other guy Feb 08 '19 at 21:03

3 Answers3

1

For sed, you have to escape each backslash with another backslash for them to be treated literally.

The s command additionally requires you to escape the delimiter and &, so it's easier to use the c command, so that doubling backslashes is the only requirement:

sed -i '/PS1/c\
export PS1="\\n\\[\\e[32;1m\\][\\[\\e[37;1m\\]\\u@\\h:\\[\\e[37;1m\\]\\w\\[\\e[32;1m\\]]\\\\$ \\[\\e[0m\\]"
' file.txt

If file.txt contains:

hello
PS1=foo
world

then after running this command, it will contain:

hello
export PS1="\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]"
world
that other guy
  • 116,971
  • 11
  • 170
  • 194
0

Just use a tool that can work with literal strings, e.g. awk:

$ awk 'BEGIN{new=ARGV[1]; ARGV[1]=""} sub(/PS1=.*/,"PS1="){$0=$0 new} 1' \
    '"\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]"' file
export PS1="\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]"

or if you prefer:

$ new='"\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]"' \
    awk 'sub(/PS1=.*/,"PS1="){$0=$0 ENVIRON["new"]} 1' file
export PS1="\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]"

sed does not have any mechanism to understand literal strings, see Is it possible to escape regex metacharacters reliably with sed for the hoops you'd need to jump through to get sed to act as if it does.

Ed Morton
  • 188,023
  • 17
  • 78
  • 185
0

You can do this using pure Bash code with:

newps1='"\n\[\e[32;1m\][\[\e[37;1m\]\u@\h:\[\e[37;1m\]\w\[\e[32;1m\]]\\$ \[\e[0m\]"'
readarray -t bashrc_lines <~/.bashrc
printf '%s\n' "${bashrc_lines[@]/PS1=*/PS1=$newps1}" >~/.bashrc

The only quoting required is to put single quotes around the exact string (including the double quotes) that is to be put to the right of PS1=.

The code requires Bash 4 (or 5) for readarray. It reads all of the '.bashrc' file into memory, but that shouldn't be a problem in practice. (If it's too big to load into memory than it's almost certainly too big to be a useful '.bashrc'.)

See Substituting part of a string (BashFAQ/100 (How do I do string manipulation in bash?)) for information about how the substitution is done.

pjh
  • 6,388
  • 2
  • 16
  • 17