On 5/11/07, Craig Skinner <[EMAIL PROTECTED]> wrote:
I'm having a wee bit of bother with a korn shell script that drives dump:

The guts of the script:

        dump="${dump} -${level}${dump_flags} ${device} | gzip -9"
...
                dump="${dump} | ${encryption} -pass file:${conf}.passwd -out"
...
        ${dump} ${file}
...
Excess arguments to dump: | gzip -9 | openssl enc -bf -salt -pass 
file:/etc/dumpster/teak.dumpster_slices.conf.passwd -out 
/tmp/tmp.MEuYIi9135/teak/_var_mail_6_Friday.dump.gz.crypto
...
If I run the full command manually, it works as expected. Soooo, I
reckon there is something wrong with my script and the manner in which
it passes arguments to dump. Any suggestions?

Shell syntax, including pipes and redirections, is only special when
it was part of the literal shell input or part of the arguments to the
'eval' builtin.  In your case, the shell read the command
    ${dump} ${file}
and didn't see any syntax characters or keywords, so that's going to
be handled after variable expansion and word-splitting as a single
command and its arguments.

The solution is to use eval to tell the command to reparse after the
variables are expanded:
   eval "${dump} ${file}"

Now, for this case, that will work just fine and is only slightly more
fragile than your existing script.  I mean, your existing script will
behave badly if someone accidentally sticks whitespace or a filename
globbing character into one of those variables.  The eval just means
that those would behave _extra_ badly, and some other punctuation
would be dangerous in those variables, such as backquotes,
dollarsigns, pipes, etc.

If this script needed to be robust when given such values in
variables, or could be passed untrusted input, then you would need to
think very carefully about when the various expansion would be done.
I would probably write the relevant lines like this:

      # Look closely: that's equal-sign, single-quote, double-quote,
dollar-sign...
      cmd='"${dump}" "-${level}${dump_flags}" "${device}" | gzip -9'
      if [[ ! -z ${encryption} ]]; then
              cmd="${cmd}"' | "${encryption}" -pass "file:${conf}.passwd" -out'
      else
              cmd="${cmd} -o"
      fi
      eval "${cmd}"' "${file}"'

With that, the only variable expanded before the eval is processed is
'cmd'. Everything else is only processed once, in the 'eval'
processing, *and* they're all inside double-quotes for that expansion,
so no whitespace splitting or shell-globbing will affect them.

Alternatively, there's this version:
      # disable globbing
      set -f
      # disable word-splitting of the result of variable or command-expansion
      IFS=
      cmd='${dump} -${level}${dump_flags} ${device} | gzip -9'
      if [[ ! -z ${encryption} ]]; then
              cmd="${cmd}"' | ${encryption} -pass file:${conf}.passwd -out'
      else
              cmd="${cmd} -o"
      fi
      eval ${cmd} \${file}


Philip Guenther

Reply via email to