Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Match a string that contains a newline using sed

I have a string like this one:

    #
    pap

which basically translates to a \t#\n\tpap and I want to replace it with:

    #
    pap
    python

which translates to \t#\n\tpap\n\tpython.

Tried this with sed in a lot of ways but it's not working maybe because sed uses new lines in a different way. I tried with:

sed -i "s/\t#\n\tpap/\t#\tpython\n\tpap/" /etc/freeradius/sites-available/default

...and many different other ways with no result. Any idea how can I do my replace in this situation?

like image 937
Romeo Mihalcea Avatar asked May 24 '14 23:05

Romeo Mihalcea


3 Answers

try this line with gawk:

awk -v RS="\0" -v ORS="" '{gsub(/\t#\n\tpap/,"yourNEwString")}7' file

if you want to let sed handle new lines, you have to read the whole file first:

sed ':a;N;$!ba;s/\t#\n\tpap/NewString/g' file
like image 180
Kent Avatar answered Oct 21 '22 11:10

Kent


This might work for you (GNU sed):

sed '/^\t#$/{n;/^\tpap$/{p;s//\tpython/}}' file

If a line contains only \t# print it, then if the next line contains only \tpap print it too, then replace that line with \tpython and print that.

like image 23
potong Avatar answered Oct 21 '22 11:10

potong


A couple of pure bash solutions:

Concise, but somewhat fragile, using parameter expansion:

in=$'\t#\n\tpap\n' # input string

echo "${in/$'\t#\n\tpap\n'/$'\t#\n\tpap\n\tpython\n'}"
  • Parameter expansion only supports patterns (wildcard expressions) as search strings, which limits the matching abilities:
  • Here the assumption is made that pap is followed by \n, whereas no assumption is made about what precedes \t#, potentially resulting in false positives.
  • If the assumption could be made that \t#\n\tpap is always enclosed in \n, echo "${in/$'\n\t#\n\tpap\n'/$'\n\t#\n\tpap\n\tpython\n'}" would work robustly; otherwise, see below.

Robust, but verbose, using the =~ operator for regex matching:

The =~ operator supports extended regular expressions on the right-hand side and thus allows more flexible and robust matching:

in=$'\t#\n\tpap' # input string 

# Search string and string to append after.
search=$'\t#\n\tpap'
append=$'\n\tpython'

out=$in # Initialize output string to input string.
if [[ $in =~ ^(.*$'\n')?("$search")($'\n'.*)?$ ]]; then # perform regex matching
    out=${out/$search/$search$append} # replace match with match + appendage
fi

echo "$out"
like image 3
mklement0 Avatar answered Oct 21 '22 11:10

mklement0