I would like to change the PS1 in my ~/.bashrc programmatically with any of the the most popular regexp tools { sed, awk or perl }. However, I have problems with special characters. Note that in the default ~/.bashrc there are three PS1 prompt variables set under different conditions, and that they are all different. I want to change only two of them, by commenting out the original PS1 line and under it modifying what used to be the original.
For illustration let me show you the segment of .bashrc before and after the modification to PS1 variable. (BTW, to increase readability I use my custom concatenation markings "join" (\\j\) and "space" (\\s\) ), where the former means the two parts are joined without any white-space char between them, but the latter allows spaces between the two.
Before:
if [ "$color_prompt" = yes ]; then
PS1='${debian_chroot:+($debian_chroot)} \\j\
\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
else
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\n\$> '
fi
unset color_prompt force_color_prompt
If this is an xterm set the title to user@host:dir
case "$TERM" in
xterm|rxvt)
PS1="[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a]$PS1"
;;
*)
;;
esac
After:
if [ "$color_prompt" = yes ]; then
# PS1='${debian_chroot:+($debian_chroot)} \\j\
\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
PS1='${debian_chroot:+($debian_chroot)} \\j\
\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\n\$> '
else
# PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\n\$> '
fi
unset color_prompt force_color_prompt
If this is an xterm set the title to user@host:dir
case "$TERM" in
xterm|rxvt)
PS1="[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a]$PS1"
;;
*)
;;
esac
I got the following working:
For those of you, who wish to try this out, let me show you what I got working, and what I've also learned is the problem with sed, and where awk and perl are better, though after playing with them, i.e., awk and perl for a day, I actually got only sed to do less than a half of what I wanted!
In particular pay attention to concatenation trick with a single-quote inside a single-quoted string replaced with {{ ' " ' " ' }}: Namely:
internal internal
single-quote single-quote
vvvvv vvvvv
aString=' this is unquoted '"'"' this is single-quoted '"'"' '
echo "[$aString]"
[ this is unquoted ' this is single-quoted ' ]
Internal single-quote is actually two single quotes and a string that happens to be a double-quoted single quote {{ ' " ' " ' }}. Which when put together inside $aString, makes that string made up of five concatenated strings:
' this is unquoted ' + "'" + ' this is single-quoted ' + "'" + ' '
Another mine you'll step on in {{ sed }} is that {{ sed }} for some reason does not handle octal representation of <Esc> character (\033) correctly, apparently it'd be fine with hex, namely, {{ \x1b }} or {{ \x1B }}, but that's not what's in the .bashrc file, because the four characters {{ \033 }} are stored literally as ASCII {{ \, 0, 3 and 3 }} though I believe the shell (Bash, Bourne or Perl for that matter) should convert these occurrences into appropriate single character they represent: the <Esc> character in this case. This looks to me like a can of worms! I spent entire weekend testing different permutations of escaped, double escaped, octal, and hex combinations with {{ sed, awk & perl }} and the only thing I got working is the following without colour-codes in {{ sed }}. Adding colour codes in the mix, just kills everything I know and and everything I tried.
This sed code works:
29
30 ps1_2=' PS1='"'"'${debian_chroot:+($debian_chroot)}\\u\@\\h:\\w\\$ '"'"''
31 ps1_2n=' PS1='"'"'${debian_chroot:+($debian_chroot)}\\u\@\\h:\\w\\n\\$> '"'"''
32
33 sed "s/$ps1_2/#&\n$ps1_2n/" ps1-tFILE.txt
Solved
Scott, thank you very much for your prompt reply, that inspired me exactly in the right direction. I solved my problem by handling smaller pieces first and then merging it all back together. Here's how I did it:
1 #!/usr/bin/env bash
2 # $Log$
3
4 # -- The following are the contents of the {{ ps1-tFILE.txt }} file:
5
6 #^ PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\] \\j\
\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
8 #^ else
9 #^ PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\n\$> '
10
11 P1=' PS1='"'"'${debian_chroot:+($debian_chroot)}'
12 P2='\\\[\\033\[01;32m\\]'
13 P3='\\u@\\h'
14 P4='\\\[\\033\[00m\\]:'
15 P5='\\\[\\033\[01;34m\\]\\w'
16 P6='\\\[\\033\[00m\\]'
17 P7='\\$ '"'"''
18
19 srchPatt_wCtrls="\($P1$P2$P3$P4$P5$P6\)\($P7\)"
20 replPatt_wCtrls='#&\n\1\\n\\$> '"'"''
21
22 # -- For the convenience I also print out all individual parts \\s\
of the match and replace patterns.
23 echo "P1=$P1"
24 echo "P2=$P2"
25 echo "P3=$P3"
26 echo "P4=$P4"
27 echo "P5=$P5"
28 echo "P6=$P6"
29 echo "P7=$P7"
30 echo "srchPatt_wCtrls=$srchPatt_wCtrls"
31 echo "replPatt_wCtrls=$replPatt_wCtrls"
32
33 ps1_o=' PS1='"'"'${debian_chroot:+($debian_chroot)}\\u\@ \\j\
\\h:\\w\\$ '"'"''
34 ps1_r=' PS1='"'"'${debian_chroot:+($debian_chroot)}\\u\@ \\j\
\\h:\\w\\n\\$> '"'"''
35
36 sed -e "s/$srchPatt_wCtrls/$replPatt_wCtrls/" \
37 -e "s/$ps1_o/#&\n$ps1_r/" ps1-tFILE.txt
38
39 exit
My test file
For those of you who have trouble with my ASCII text concatenation conventions I'm also including the contents of my test file (ps1-tFILE.txt) in a scrollable window:
$> cat ps1-tFILE.txt
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
else
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
Thanks again, it helped me to sleep it over, and get inspirations from Scott:)