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
.
Just for completeness, you don't need all those (") nor the final $(echo ...)
.
Here's the simplified version of your assignments that produce the same
effect:
STARTIME=$(date +"%T")
ENDTIME="$STARTIME today + 10 seconds"
CALL="date -d '$ENDTIME' +'%H:%M:%S'"
Note how you don't need to quote when doing var=$(...) but you do usually
with var="many words":
a=$(echo 'a b'); echo "$a" # result: a b
Inside (") a (') has no special significance, and vice-versa, eg:
a="that's nice"; echo "$a" # result: that's nice
a='that "is nice'; echo "$a" # result: that "is nice
Best Answer
There are two problems here. First of all, what you are doing is absolutely the wrong way to process the files in a directory and will break if your file names contain newlines or other strangeness. See http://mywiki.wooledge.org/ParsingLs for more.
That said, the colors of
ls
are optional. In many Linux distributions, the commandls
is actually aliased tols --color=tty
which enables colors whenls
is printing to a tty (as opposed to awhile
loop, for example). However, aliases are not enabled in scripts usually so when you runls
from your script, you're just running normalls
with no colors.So, the first ugly workaround would be to call
ls --color=always
. That will let you echo with colors. However, this is almost certainly a bad idea as I mentioned in the first paragraph. For one thing, if you just want to print each line out, why don't you just runls
and forget thewhile
loop?If you do need to process the files for some other reason and still need to use
ls
as well, use globbing to get the list of files and then runls
on each of them manually:That will not break on weird file names and will still show you the colors as you requested.