1

I'm trying to write a script that would replace that line:

 [ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@\h \W]\\$ "

with that line:

# [ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@\h \W]\\$ "

and that will add that new line:

[ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@\h \D{%T} \W]\\$ "

to the /etc/bashrc file. Basically, I want the script to comment the old settings and add a timestamp next to the username in the prompt (the new setting). I have tried to do the first part like this:

pattern=' [ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@\h \W]\\$ "'
sudo sed 's/${pattern}/#${pattern}/' < /etc/bashrc 

But it didn't work, I think it's becouse of the special chars in the string. But I'm not sure which chars do I need to escape. The last part supposed to be just something like this:

sed -i '  [ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@\h \D{%T} \W]\\$ "' /etc/bashrc

Will apriciate some guidness.

Thanks

1
  • 2
    1st rule before any attempt to answer: don't sudo or work on system files (/etc/bashrc) while you haven't thoroughfully tested your shell script on crash files without any priviledge.
    – dan
    Feb 6, 2018 at 14:31

3 Answers 3

2
  1. The single quotes in your sed script prevent the ${pattern} from being expanded. You'd have to use double quotes (but this would lead to the mentioned problem with special chars)
  2. Use sed addressing with enough of the given line to identify it and then insert the commenting like this: /^ *\[ *"$PS1 =/s/^/#/
  3. Use the a command of sed to append a given line

In your case you just want to add something to the line, so

sed 's/\( *\[ "$PS1" = "..s-..v...$ " \] && PS1="\[[email protected] \)\(.W]..$ "\)/#\1\2\
\1\\D{%T} \2/' /etc/bashrc 
2
  • It didn't work. It's printed the file like the changes took place (like cat the bashrc after I ran the sed), but when I open the file in vim there are no changes.
    – lakerda
    Feb 6, 2018 at 14:18
  • If you get the desired output, add the -i option to actually perform the changes. It's always a good idea to test without -i first, when changing system files.
    – Philippos
    Feb 6, 2018 at 14:21
0

To do this kind of substitution of complex pattern with sed:

sed 's/${pattern}/#${pattern}/'

you have to force evaluation of pattern this way:

sed 's/'${pattern}'/#'${pattern}'/'

Check that this achieve exactly what you want on temporary file before trying to touch /etc/bashrc and use sudo (Moreover, before using sudo you should check you are really using the right one to avoid to use a fake one).

0

If you like to replace a whole line without regex, you could also get the line number first:

LNO=$(grep -FN "$pattern" </etc/bashrc | cut -d':' -f1)

and replace the line with commented pattern and new line:

[ "$LNO" ] \
&& sed -i "${LNO}s/.*/#$pattern\n$newline/" /etc/bashrc

This one is also clearer to read months later.

For testing purposes I always prefer to sed into a temporary file first (without -i option), and rename it later so I don't harm my config.

But I also found that this method does not work with patterns containing [,],$ and &, the patterns also need some masking in this order:

pattern=${pattern//\[/\\\[}
pattern=${pattern//\]/\\]}
pattern=${pattern//\$/\\$}
pattern=${pattern//\&/\\&}
pattern=${pattern//\\/\\\\}

which leads to following function:

#!/bin/bash

declare -a commentAndReplaceMask=('[' ']' '$' '&')
function commentAndReplace () {
  local p="$1"  # pattern
  local s="$p" # sed pattern
  local r="$2"  # replacement
  local f="$3"  # file

  echo args:
  echo p: $p
  echo r: $r
  echo s: $s

  s=${s//\\/\\\\}
  r=${r//\\/\\\\}
  for m in ${commentAndReplaceMask[@]}; do
    s=${s//$m/\\$m}
    r=${r//$m/\\$m}
  done

  echo prepared for sed:
  echo p: $p
  echo r: $r
  echo s: $s

  LNO=$(grep -Fn "$p" <$f | cut -d':' -f1)

  [ "$LNO" ] \
  && sed "${LNO}s/.*/# $s\n$r/" <$f >${f}.tmp

  # mv "${f}.tmp" "$f"
}

commentAndReplace "$@"

You must log in to answer this question.

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