My script looks like:

opts="-x ''"
curl http://somepage $opts

I want the string in $opts appended to the command. I use bash -x test.sh to check the expansion and see that the the single-quotes are removed.

If I change it to:

opts="-x \'\'"

After expansion, there are 4 single-quotes.

  • Are you sure they are actually removed in the unescaped version and not just passed as a blank word?
    – Caleb
    May 9 '11 at 9:46
  • Also, you mention "bash" in your subject and tag, but named your script ".sh", then say you executed it manually with bash. I got different results doing this in bash 4.2.0. Are you sure you are actually using bash and not some other shell with bash emulation?
    – Caleb
    May 9 '11 at 9:50
  • @Caleb: If bash <file> is used, then it is bash, irrespective of filename. (I have yet to see a shell that emulates 'bash' down to providing a binary with the same name...)
    – user1686
    May 10 '11 at 20:22
  • @grawity: Actually there are several that do, most notably busybox. However the main point was that, because his question had mix and match bits, I wanted to make sure the asker understood that he was being ambiguous because you can easily hit inconsistencies if you don't understand that different shells act differently and sh and bash aren't the same.
    – Caleb
    May 11 '11 at 0:04

What exactly do you see? With the script

opts="-x ''"
echo curl http://somepage $opts
opts="-x \'\'"
echo curl http://somepage $opts

With bash 3.2.39 or 4.1.5, I see

+ opts='-x '\'''\'''
+ echo curl http://somepage -x ''\'''\'''
curl http://somepage -x ''
+ opts='-x \'\''\'\'''
+ echo curl http://somepage -x '\'\''\'\'''

The first call to curl (well, echo curl) has a last argument consisting of two characters ''. The trace escapes special characters: ' appears as '\'' (a common idiom to “escape” single quotes inside single quotes). Formally, ''\'''\''' consists of an empty single-quoted string '' followed by the backslash-quoted character \', then again '', again \', and a final ''. (Ksh shows this as the slightly more readable $'\'\''.) The second call passes four characters \'\'.

Under the normal sh parsing rules, you can't make an empty argument by expanding an unquoted variable. Word splitting cuts only where there's a non-whitespace or quoted character.

Since you're using bash, you can put multiple options in an array. This also works in ksh and zsh.

opts=(-x "")
curl http://somepage "${opts[@]}"

For this particular case, you can override the environment variable instead.

http_proxy= curl http://somepage
  • 2
    +1 for using arrays. If they're available, it's insanity to use anything else. Compare the first part of this answer with the simplicity of the array solution.
    – camh
    May 9 '11 at 12:22

This is because what you want is to pass a literal empty string to curl, but what you get is a set of literal quotes since they are already quoted. One reference points to another which simply recommends using a function:

    curl http://somepage "$@"
download -x ''

If you want to observe what your script is actually doing, try running set -x before it.

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.