简体   繁体   中英

From bash prompt to a bash function: How to escape args and quotes properly?

I have a CouchDB database that contains some daily updated status information. I can use curl to query the database from my bash prompt:

curl 'http://localhost:5984/db/_design/state/_view/stateinfo?group=true&startkey=\["2016-02-10",0\]&endkey=\["2016-02-10\u9999",\{\}\]'

Now I want to write a little function dbq in my .bash_aliases that can be used like so: dbq mm-dd where mm-dd is a date such as 02-10 . I tried (among other variations):

dlq() { curl  \'http://localhost:5984/db/_design/state/_view/stateinfo?group=true\&startkey=\[2016-{$1},0\]\&endkey=\[2016-{$1}\u9999,\{\}\] \' ;}

I just can't get the argument interpolation (of $1 ) and the escaping of brackets, quotes, slashes and ampersands in the bash function right. Any ideas on how to do this properly? (BTW, this escaping business when transitioning from a working bash prompt solution towards a reusable bash function with arguments has slowed me down several times. Any hints and pointers to some helpful resources are much appreciated.)

The body of a function is effectively quoted (one reason they are superior to aliases), so you don't need to escape the single quote or anything inside them. You do, however, need to use double quotes so that $1 is expanded.

Something like...

dlq() {
    baseurl="http://localhost:5984/db/_design/state/_view/stateinfo"
    curl "$baseurl?group=true&startkey=[2016-{$1},0\]&endkey=[2016-{$1}\u9999,{}]"
}

(Please double-check the parameters; I'm not sure what was escaped erroneously and what might need escaping for the API.)

I find the fact that you need to pass backslashes in your original command very odd, and worry a bit that it may indicate that your backend is vulnerable to some sort of remote-code-execution attack. But putting that aside:

The thing to remember about bash quoting is that the rules around ' are very short and simple, but are so short and simple that they often surprise people. Specifically, the rule is this: absolutely nothing is special until the next ' mark. Nothing. Not backslashes, not newlines, nothing. Everything gets passed through.

This is different from most programming languages, which trips people up.

In your original command line, when you pass this:

curl 'http://localhost:5984/db/_design/state/_view/stateinfo?group=true&startkey=\["2016-02-10",0\]&endkey=\["2016-02-10\u9999",\{\}\]'

That means that the argument to curl is literally

http://localhost:5984/db/_design/state/_view/stateinfo?group=true&startkey=\["2016-02-10",0\]&endkey=\["2016-02-10\u9999",\{\}\]

with all the backslashes intact.

Now, in your function the easiest way to pass what you want is to use the fact that two adjacent strings in bash get passed together as a single argument, and do:

dlq() {
  curl  'http://localhost:5984/db/_design/state/_view/stateinfo?group=true&startkey=\["2016-'"$1"'",0\]&endkey=\["2016-'"$2"'\u9999",\{\}\]'
}

Note that what I have there is a string in single quotes that ends with "2016- , then a string in double quotes that is "$1" , then a string in single quotes that begins with a double quote character and continues until it also ends in "2016- and then a double quoted "$2" , and then a single quoted string until the end of the line.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM