showargs
command is quite helpful for this. There's an interesting post on the issue here, I'm quoting Brian Dessent:> I want to pass data arguments to curl using a bash variable instead of supplying
> them explicitly. So I defined a variable, like this:
>
> DOCDATA='-F "title=Hello World!" -F "body=Content goes here."'
>
> however, when I now invoke curl with that variable as an argument, like this:
> curl (url) $DOCDATA
>
> then I will get curl errors:
>
> Connection #0 to host localhost left intact
> * gethostbyname(2) failed for World!"
> * Couldn't resolve host 'World!"'
> * Closing connection #1
This has everything to do with how shell quoting works and nothing to do
with curl. Here's a simplified example that uses a C program "showargs"
that does nothing but print out its argv[]. (I find this program very
useful to keep around because if you have a problematic command you can
simply copy/paste or uparrow and insert 'showargs' at the beginning of
it.)
$ x='a b "c d"'
$ echo $x
a b "c d"
$ showargs $x
argv[0] = 'showargs'
argv[1] = 'a'
argv[2] = 'b'
argv[3] = '"c'
argv[4] = 'd"'
As you can see when the shell expands $x it does not see a string
containing three words, it sees four -- there are simply four things
separated by spaces (or more precisely, IFS.) The shell doesn't
consider quotes as meaningful in this context, so the fact that there
are double quotes inside x doesn't matter.
If you want to force the shell to evaluate x as an expression instead of
simply expanding it into words, then you have to use eval:
$ eval showargs $x
argv[0] = 'showargs'
argv[1] = 'a'
argv[2] = 'b'
argv[3] = 'c d'
But this is a dangerous solution to rely on, because if your "Hello
world" was actually "I have $4 in my pocket", it would be mangled
because now you're telling the shell to not just split words but to
evaluate the string (as if you'd typed it), and it would see $4 as a
variable and try to expand it -- most likely into nothing. So you'd
have to make sure that all of the metacharacters in the text of your
variables are quoted!
This can get very ugly, because essentially what you're doing is
combining multiple words into one word, only to turn right around and
parse them back out into multiple words -- and all the quoting has to be
just right to make that roundtrip correct. It's much simpler just to
use one variable where you intend one word. For example I would have
written:
title='Hello World!'
body="Content goes here."
url="http://foo/bar"
...
curl "$url" -F title="$title" -F body="$body"
Note that when you use a variable that might contain spaces and you
*don't* want it to be split into words, you need to quote it as "$foo".
This allows foo to have spaces in it but still only represent one word,
which is what you want:
$ showargs curl "$url" -F title="$title" -F body="$body"
argv[0] = 'showargs'
argv[1] = 'curl'
argv[2] = 'http://foo/bar'
argv[3] = '-F'
argv[4] = 'title=Hello World!'
argv[5] = '-F'
argv[6] = 'body=Content goes here.'
No comments:
Post a Comment