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'
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

  • 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 '12 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 – Drake Clarris Nov 8 '12 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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.