views:

210

answers:

2

Hello Shell Experts,

In the following, the echo output is right, but the pgm is not receiving the flags correctly. Appreciate any insights.

script file:
flags="-umc -v -v "
r="";for d in `ls -d /tmp/passenger*`; do r="$r -x  $d"; done
flags="$flags $r"
echo $flags
/usr/sbin/tmpwatch "$flags" -x /tmp/.X11-unix -x /tmp/.XIM-unix \
    -x /tmp/.font-unix -x /tmp/.ICE-unix -x /tmp/.Test-unix 240 /tmp

Output of sh -x < script

sh -x < ./tmpwatch
+ flags='-umc -v -v '
+ r=
++ ls -d /tmp/passenger.15264
+ for d in '`ls -d /tmp/passenger*`'
+ r=' -x  /tmp/passenger.15264'
+ flags='-umc -v -v   -x  /tmp/passenger.15264'
+ echo -umc -v -v -x /tmp/passenger.15264
-umc -v -v -x /tmp/passenger.15264
+ /usr/sbin/tmpwatch '-umc -v -v   -x  /tmp/passenger.15264' \
   -x /tmp/.X11-unix -x /tmp/.XIM-unix -x /tmp/.font-unix \
   -x /tmp/.ICE-unix -x /tmp/.Test-unix 240 /tmp
/usr/sbin/tmpwatch: invalid option --
tmpwatch 2.9.7 - (c) 1997-2006 Red Hat, Inc. All rights reserved.
This program may be freely redistributed under the terms of the
GNU General Public License.

I think I need to feed $flags into the command in a different way...

Larry

+2  A: 

Don't put the quotes around the variable if you want the words in that variable to be interpreted as separate arguments to the command.

Instead of this:

/usr/sbin/tmpwatch "$flags"

Use this:

/usr/sbin/tmpwatch $flags


Re your comments:

It makes no difference if the script is run from cron. The script is interpreted by sh not cron.

Single-quotes in the shell prevent variable expansion. Otherwise, variables do expand -- whether they're within double-quotes or unquoted. Try it:

$ food=banana
$ echo $food      # echoes banana
$ echo "$food"    # echoes banana
$ echo '$food'    # echoes $food literally

The other effect of quotes, whether single or double, is to make a string be passed to the command as a single word instead of multiple words separated by any whitespace that was in the expanded variable value.

Bill Karwin
Thanks Bill. The original script (from RedHat) had the quotes (before the passenger directories line was added). Anyhow, I thought the quotes were needed to trigger variable interpolation. Now I know better. Does it make any difference that the script is in /etc/cron.daily for use by crontab? Thanks again, Larry
Larry K
A: 

What Bill said. Here's a crazier to write this, by the way, if you're using bash:

#!/bin/bash    

# Store file names in an array variable. Same as (`ls -d /tmp/passenger*`),
# by the way, but the ls is unnecessary.
files=(/tmp/passenger*)

# Add each file name to $flags, adding -x in front of each.
# "/#/-x " means search for an empty string at the beginning of
# each array item, and replace it with "-x ". Effectively, that
# just prepends "-x " to each.
flags="-umc -v -v ${files[*]/#/-x }"

# No quotes around $flags, so each word is passed as a separate
# command-line argument to tmpwatch.
/usr/sbin/tmpwatch $flags -x /tmp/.X11-unix -x /tmp/.XIM-unix \
    -x /tmp/.font-unix -x /tmp/.ICE-unix -x /tmp/.Test-unix 240 /tmp

From the bash man page:

${parameter/pattern/string}

The pattern is expanded to produce a pattern just as in pathname expansion. Parameter is expanded and the longest match of pattern against its value is replaced with string. If pattern begins with /, all matches of pattern are replaced with string. Normally only the first match is replaced. If pattern begins with #, it must match at the beginning of the expanded value of parameter. If pattern begins with %, it must match at the end of the expanded value of parameter. If string is null, matches of pattern are deleted and the / following pattern may be omitted. If parameter is @ or *, the substitution operation is applied to each positional parameter in turn, and the expansion is the resultant list. If parameter is an array variable subscripted with @ or *, the substitution operation is applied to each member of the array in turn, and the expansion is the resultant list.

John Kugelman
Thanks John. I'm modifying a RH-supplied system cron file so my assumption is /bin/sh is being used.
Larry K
`sh` is really `bash` on Red Hat, but you can add `#!/bin/bash` at the top to pick your shell explicitly.
John Kugelman