2

I want to write a script 'test.sh' that will take a user's input and replace all special characters with a '\' + the character. My script:

#!/bin/bash
echo 'input='"$1"
arg=`echo "$1" | sed 's:[]\[\^\$\.\*\/]:\\&:g'`
echo 'modified input='"$arg"

My command works on the string 'xy', which does not have any special characters. I run this in my terminal:

test.sh xy

And I obtain:

input=xy
modified input=xy

However, when I run this:

test.sh x.y

I get:

input=x.y
modified input=x&y

I don't understand why this script is not working. I expect to get:

input=x.y
modified input=x\.y

I think the problem lies in this sed command but I'm not sure where:

sed 's:[]\[\^\$\.\*\/]:\\&:g'

2 Answers 2

4

I don't think you are capturing the group right. Try this?

sed 's:\([]\[\^\$\.\*\/]\):\\\1:g'

Edit: nevermind, I wasn't aware of the relevance of &. The problem is you need to extra escape the slashes in replacement because of the parsing and passing to sub shell.

sed 's:[]\[\^\$\.\*\/]:\\\\&:g'

Also, if you used $(command) instead of backticks, you don't need the extra \'s

2
  • Yes, if I add two more '\' as you did will work. But I don't see why they are needed. Is there a reference you can point me to understand this? Also, not sure what you mean regarding $(command)
    – drapkin11
    Nov 7, 2012 at 22:15
  • 1
    enclosing commands in backticks uses simple substitution - so the the command is parsed by the current shell. $(command) opens a subshell, so anything inside the parens runs as if on its own command line. See for more info: wiki.bash-hackers.org/syntax/expansion/cmdsubst Nov 8, 2012 at 14:58
1

So the task is to write a sed substitution that escapes all special characters (defined as the characters []^$.*/, and I added \ too) in a string.

The substitution might look like

s/[][\^$.*/]/\\&/g

Note that we don't really have to escape any of the characters in the [...] set (the \ is treated literally too, so we can't escape anything in there), and that the only thing we have to make sure of is that ] is in the very beginning of it.

So the script (rewritten as a shell function, and revamped in other ways) becomes

function escape
{
    printf '%s\n' "$1" | sed 's/[][\^$.*/]/\\&/g'
}

Testing:

$ escape 'hello world'
hello world

$  escape '*.*'
\*\.\* 

$ escape '\/'
\\\/

$ escape '/\'
\/\\

$ escape 's/[][\^$.*/]/\\&/g'
s\/\[\]\[\\\^\$\.\*\/\]\/\\\\&\/g

You must log in to answer this question.

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