I'm working with a HTTP API that demands a very particular set of signed headers + JSON body. And I really want to cURL it for debugging and sanity in general.

So, I've written a small script that, given the hostname, path and body, does all the mangling and then writes out what the cURL command line should be. eg.

./sign example.com /api/v1/foo/bar '{"foo":"bar"}'
example.com/api/v1/foo/bar -H 'x-sign:XXXXX', -H ... --data-binary '{"foo":"bar","sign":"xxx"}'

(Yes, it does seem quite complicated...)

I would expect this to be easily shell-able (in ZSH) thusly:

curl -v $(./sign ...)

But that gives me all sorts of quoting mistakes (or tries to curl the header-stuff as URLs, depending on how I do the quoting).

The only working way feels way too clunky to be ... real:

sh -c "curl -v $(./sign ...)"

I'm thinking I'm missing some fairly quoting-options of sorts here. Any pointers on how to get this "nice"?

  • 1
    Welcome to U&L! Would it be reasonable to have the shell script execute curl directly? You could use something like set -x to see the command as it's being executed. That way, you have one less level of quoting to deal with. – Jeff Schaller Aug 22 '18 at 14:05

Your ./sign outputs shell code, so it should be evaluated as such, either by sh with your sh -c or the current shell with eval:

eval "curl -v $(sign...)"

With zsh you can also only interpret the quoting in it (not do the expansions that that shell code may do) with:

curl -v "${(@Q)${(z)"$(sign)"}}"

Where (z) interprets the quoting, and (Q) removes the quotes (and (@) within quotes preserves the empty elements).

If sign outputs "foo bar" "$(echo test)", the first one would call curl with foo bar and test as arguments, while the second one would call curl with foo bar and $(echo test) as arguments.

|improve this answer|||||

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.