Reputation: 284
It's my first post on SO (long time lurker though) so I apologies in advance for the numerous "faux pas" and other mistakes I am certainly about to make.
I've been looking on google for a while now trying to find an answer to how quotes are parsed when inside parameter expansion that are inside double quotes and it seems that I either have the wrong keywords or a very twisted mind for attempting this.
For example, if I have a string like It's a complicated string
, I would like to transform that string into the sequence It'\''s a complicated string
using bash's parameter expansion ${parameter/pattern/string}
. I know I can achieve that result using one of many other builtin or external tool (I'm quite fond of sed myself), but this question really is about understanding what is going on in bash's mind so that I can put my own mind to ease.
Bash's reference don't seem to specify what happen in that special case when describing its "pattern" and the closest question on SO doesn't seem to work in my case :
$ echo "$str"
It's a complicated string
$ echo "${str//'/'\''}"
> ^C
$ echo "${str//'/'\''}"
> ^C
$ echo "${str//\'/'\''}"
> ^C
$ echo "${str//\'/\'\''}"
> ^C
$ echo "${str//\'/\'\'\'}"
It\'\'\'s a complicated string
$ echo "${str//\\'/\'\'\'}"
It's a complicated string
$ echo "${str//\\'/\\'\'\'}"
It's a complicated string
$ echo "${str//\\'/\\'\\'\'}"
It's a complicated string
$ echo "${str//\\'/\\'\\'\\'}"
It's a complicated string
$ echo "${str//\\\'/\\'\\'\\'}"
> ^C
$ echo "${str//\\\'/\\\'\\'\\'}"
It's a complicated string
$ echo "${str//\\\'/\\\'\\\'\\'}"
> ^C
$ echo "${str//\\\'/\\\'\\\'\\\'}"
It's a complicated string
(The > ^C
lines means that the quotes were not parsed correctly and I was prompted for more input, which I ruthlessly deny each time using Ctrl-C.)
Would any of you be kind enough to explain how exactly bash sees this? I really hope it's just a communication problem between us, I kinda like him. :)
EDIT:
For those wondering, Etan Reisner's answer works :
$ q=\'
$ echo "${str//\'/$q\'$q}"
It'\''s a complicated string
As for sputnick's answer, I'm even more puzzled :
$ echo "${str//\047/\047\\\047\047}"
It's a complicated string
$ echo "${str//\047/\047\047}"
It's a complicated string
$ echo "${str//\'/\047\'\047}"
It\047\'\047s a complicated string
$ echo "${str//\'/\047\047\047}"
It\047\047\047s a complicated string
$ echo "${str//'/\047\047\047}"
> ^C
$ echo "${str//\047/\047\047\047}"
It's a complicated string
$ echo "${str//\047/\047\\\047\047}"
It's a complicated string
EDIT2 :
Apparently this is a bug affecting at least bash 4.1 and 4.2 and fixed in bash 4.3. Therefore, there is nothing to understand from the above test.
Upvotes: 4
Views: 1175
Reputation: 531345
The following works (with or without double quotes):
echo "${str//\'/\'\\\'\'}"
Each single quote is escaped with a backslash to prevent it from beginning a single-quoted string. The literal backslash is also escaped in the replacement pattern.
Direct copy-and-paste from a bash
4.3 session:
$ str="It's a complicated string"
$ echo "${str//\'/\'\\\'\'}"
It'\''s a complicated string
$ echo ${str//\'/\'\\\'\'}
It'\''s a complicated string
The output in bash
3.2 is identical.
Upvotes: 2
Reputation: 80941
I can't explain what bash is doing exactly but similarly to @sputnick my suggestion is to just not play the game.
q=\'
echo "${str//\'/$q\'$q}"
Upvotes: 1
Reputation: 185254
Instead of trying weird escaping game, try to use ascii
representation of the single quote : \047
See
man 7 ascii
Upvotes: 1