9

In my bash script, i am trying to execute following Linux command:

sed -i "/$data_line/ d" $data_dir

$data_line is entered by user and it may conatain special characters that could brake regex. How can i escape all of the possible special characters in $data_line before i execute sed command?

skujins
  • 375
  • 3
  • 5
  • 13
  • how to escape regular expressions in bash http://stackoverflow.com/questions/11856054/bash-easy-way-to-pass-a-raw-string-to-grep/16951928#16951928 – Riccardo Galli Jun 06 '13 at 00:28

3 Answers3

6
grep -v -F "$data_line" "$data_dir" > ...
Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
6

You might be able to use this technique to protect the selector. The lines marked with "*****" below are the significant lines. The others are mostly for testing and demonstration. The key is to use a character that doesn't appear in the user input to delimit the selector address.

data_line='.*/ s/GOLD/LEAD/g;b;/.*'    # scary user input
candidates='/:.|@#%^&;,!~abcABC'       # *****   # (make it as long as you like)
char=$(echo "$candidates" | tr -d "$data_line")    # *****
char=${char:0:1}   # ***** choose the first candidate that doesn't appear in the user input

if [ -z "$char" ]    # ***** this test checks for exhaustion of the candidate character set
then
    echo "Unusable user input. Recommendation: cigarette and blindfold."
    exit 1
fi

# test without protection
excitement="GOLD, I tell you, thar's GOLD in them thar hills!" 
echo "$excitement" | sed "/$data_line/ d"
# output: "LEAD, I tell you, thar's LEAD in them thar hills!"

# test WITH protection
echo "$excitement" | sed "\\${char}${data_line}${char} d"    # *****
# output: "GOLD, I tell you, thar's GOLD in them thar hills!"

# test WITH protection and useful user input
data_line="secret"
mystery="The secret map is tucked in a hidden compartment in my saddle bag."
echo -e "$excitement\n$mystery" | sed "\\${char}${data_line}${char} d"
# output: "GOLD, I tell you, thar's GOLD in them thar hills!"
Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
  • Thanks Dennis for the detailed answer. I will mark it as my accepted answer, because it gives the answer to what I asked in my question. But I will use Ignacio technique because it does what i need in much cleaner way IMO. – skujins May 29 '10 at 09:41
  • The third line could be `char=${candidates//[$data_line]}` instead of using `echo` and `tr`. – Dennis Williamson May 29 '10 at 12:27
0

It's an old question, but for those still coming here, sed allows you to use a delimiter other than the forward slash.

For my script I switched from sed -i 's/$OLD_URL/$NEW_URL/g' to sed -i 's|$OLD_URL|$NEW_URL|g', as my URLs contained forward slashes, but not pipes.

Mitch
  • 1,839
  • 16
  • 23