Your quoting is wrong. When you write $CMD
with no quotes, the value of $CMD
is broken up into “words” at each whitespace sequence¹ (the words can contain any non-whitespace character including punctuation), and then each word undergoes globbing (i.e. wildcard expansion). Note that quotes in the value of CMD
, in particular, are untouched: quotes have a meaning in the syntax of shell scripts but not in variable substitution. After this, the first word becomes the name of the command to execute, and subsequent words are the command's arguments.
In your example, assuming $KEYNAME
is somekeyname
and $HZID
is somehzid
, then the
command and arguments are:
./dnscurl.pl
--keyname
$KEYNAME
--
-X
POST
-H
"Content-Type:
text/xml;
charset=UTF-8"
--upload-file
/tmp/file.xml
https://route53.amazonaws.com/2010-10-01/hostedzone/somehzid/rrset
Note that text/xml;
appears as the first non-option argument; clearly the Perl script passes that argument down to curl
. The --
in the argument list is unrelated to your problem.
There's no way to stuff a command line into a variable. A (simple) variable is the wrong tool for that: it contains a string, but a command line is a list of strings (the command, and its arguments). You can stuff a command name and its argument into an array variable:
CMD=(./dnscurl.pl --keyname "$KEYNAME" --
-X POST -H "Content-Type: text/xml; charset=UTF-8"
--upload-file /tmp/file.xml
"https://route53.amazonaws.com/2010-10-01/hostedzone/$HZID/rrset")
RESULT=$("${CMD[@]}")
The strange-looking syntax "${CMD[@]}"
expands the array variable CMD
to the list of words in the array. The double quotes prevent expansion of words inside the array, and [@]
is needed for historical reasons to tell the shell that you want to expand an array.
Another way to remember a command line, or an arbitrary shell snippet, for later use, is a function.
cmd () {
./dnscurl.pl --keyname "$KEYNAME" -- \
-X POST -H "Content-Type: text/xml; charset=UTF-8" \
--upload-file /tmp/file.xml \
"https://route53.amazonaws.com/2010-10-01/hostedzone/$HZID/rrset"
}
RESULT=$(cmd)
¹ More precisely, according to the value of IFS
.
A function cannot affect its caller's positional parameters. This is by design: positional parameters are meant to be private to the function.
Make your function work on an array.
myfunction () {
local _myfunction_arrayname=$1
shift
… # work on the positional parameters
eval "$_myfunction_arrayname=(\"\$@\")"
}
myfunction foo "$@"
set -- "${foo[@]}"
In ksh93 and bash, there's a roundabout way to do something approaching by combining an alias and the .
(source
) builtin with a process substitution. Example.
alias myfunction='. <(echo myfunction_body \"\$@\"; echo set -- "\"\${new_positional_parameters[@]}\"")'
Put the meat of the work of the function in myfunction_body
and make it set the array new_positional_parameters
. After a call to myfunction
, the positional parameters are set to the values that myfunction_body
puts in new_positional_parameters
.
Best Answer
You can't unset it, but you may shift
$2
into$1
:shift
will shift all positional parameters one step lower. It is common for e.g. command line parsing loops (that does not usegetopt
/getopts
) to shift the positional parameters over in each iteration while repeatedly examining the value of$1
. It is uncommon to want to unset a positional parameter.By the way,
unset
takes a variable name, not its value, sounset $1
will in effect unset the variablebon
(had it been previously set).