Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replacing special characters in a shell script using sed

Tags:

shell

sh

sed

I am trying to write a shell script that will replace whatever characters/strings I choose using sed. My first attempt worked with the exception of special characters. I have been trying to use sed to fix the special characters so that they too will be searched for or replaced. I decided to simplify the script for testing purposed, and just deal with a single offending character. However, I am still having problems.

Edited Script

#! /bin/sh
oldString=$1
newString=$2
file=$3

oldStringFixed=$(echo "$oldString" | sed 's/\\/\\\\/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\[/\\\[/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\]/\\\]/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\^/\\\^/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\*/\\\*/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\+/\\\+/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\./\\\./g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\$/\\\$/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\-/\\\-/g')

sed -e "s/$oldStringFixed/$newString/g" "$file" > newfile.updated
mv newfile.updated "$file"#! /bin/sh

In case it is not clear, I am trying to search through oldString for the [ character, and replace it with an escaped version and assign the results to oldStringFixed (do I need the backticks for this?). The bottom two lines are slightly modified versions of my original script that I believe works correctly.

When I echo the fixed string, nothing is displayed, and sed outputs an error

sed: can't read [: No such file or directory

Can anyone explain what Is wrong with my first sed line?

EDIT:

Thanks to Jite, the script is working better. However, I am still having a problem with replacing single quoted characters with spaces, i.e. ' *'. The new version is above.

like image 925
user3074091 Avatar asked Dec 06 '13 11:12

user3074091


1 Answers

I suggest two improvements:

  1. Do not stack calls to sed as you do, instead pack all of them in a single function, as escape_string below.

  2. You can use a fancy delimiter for the sed substitute command to avoid issues linked to / being part of the strings involved.

With these changes, your script looks like:

#! /bin/sh
oldString="$1"
newString="$2"
file="$3"

escape_string()
{
   printf '%s' "$1" | sed -e 's/[][\\^*+.$-]/\\\1/g'
}

fancyDelim=$(printf '\001')

oldStringFixed=$(escape_string "$oldString")
sed -e "s$fancyDelim$oldStringFixed$fancyDelim$newString${fancyDelim}g" "$file" \
  > newfile.updated
mv newfile.updated "$file"
like image 92
The Show that never ends Avatar answered Nov 15 '22 05:11

The Show that never ends