Quoting command-line arguments in shell scripts

Tags: wine shell unix

The following shell script takes a list of arguments, turns Unix paths into WINE/Windows paths and invokes the given executable under WINE.

#! /bin/sh

if [ "${1+set}" != "set" ]
  echo "Usage; winewrap EXEC [ARGS...]"
  exit 1



for p in "[email protected]";
  if [ -e "$p" ]
    p=$(winepath -w $p)
  ARGS="$ARGS '$p'"

CMD="wine '$EXEC' $ARGS"
echo $CMD

However, there's something wrong with the quotation of command-line arguments.

$ winewrap '/home/chris/.wine/drive_c/Program Files/Microsoft Research/Z3-1.3.6/bin/z3.exe' -smt /tmp/smtlib3cee8b.smt
Executing: wine '/home/chris/.wine/drive_c/Program Files/Microsoft Research/Z3-1.3.6/bin/z3.exe' '-smt' 'Z: mp\smtlib3cee8b.smt'
wine: cannot find ''/home/chris/.wine/drive_c/Program'

Note that:

  1. The path to the executable is being chopped off at the first space, even though it is single-quoted.
  2. The literal "\t" in the last path is being transformed into a tab character.

Obviously, the quotations aren't being parsed the way I intended by the shell. How can I avoid these errors?

EDIT: The "\t" is being expanded through two levels of indirection: first, "$p" (and/or "$ARGS") is being expanded into Z:\tmp\smtlib3cee8b.smt; then, \t is being expanded into the tab character. This is (seemingly) equivalent to

echo $Z

which yields


and not

zy  yz

UPDATE: eval "$CMD" does the trick. The "\t" problem seems to be echo's fault: "If the first operand is -n, or if any of the operands contain a backslash ( '\' ) character, the results are implementation-defined." (POSIX specification of echo)

  • bash’s arrays are unportable but the only sane way to handle argument lists in shell
  • The number of arguments is in ${#}
  • Bad stuff will happen with your script if there are filenames starting with a dash in the current directory
  • If the last line of your script just runs a program, and there are no traps on exit, you should exec it

With that in mind

#! /bin/bash

# push ARRAY arg1 arg2 ...
# adds arg1, arg2, ... to the end of ARRAY
function push() {
    local ARRAY_NAME="${1}"
    for ARG in "${@}"; do
        eval "${ARRAY_NAME}[\${#${ARRAY_NAME}[@]}]=\${ARG}"

PROG="$(basename -- "${0}")"

if (( ${#} < 1 )); then
  # Error messages should state the program name and go to stderr
  echo "${PROG}: Usage: winewrap EXEC [ARGS...]" 1>&2
  exit 1


for p in "${@}"; do
  if [ -e "${p}" ]; then
    p="$(winepath -w -- "${p}")"
  push EXEC "${p}"

exec "${EXEC[@]}"

I you do want to have the assignment to CMD you should use

eval $CMD

instead of just $CMD in the last line of your script. This should solve your problem with spaces in the paths, I don't know what to do about the "\t" problem.

By : WMR

Use the HorizontalAlignment and VerticalAlignment layout properties. They control how an element uses the space it has inside its parent when more room is available than it required by the element.

The width of a StackPanel, for example, will be as wide as the widest element it contains. So, all narrower elements have a bit of excess space. The alignment properties control what the child element does with the extra space.

The default value for both properties is Stretch, so the child element is stretched to fill all available space. Additional options include Left, Center and Right for HorizontalAlignment and Top, Center and Bottom for VerticalAlignment.

By : urini

This video can help you solving your question :)
By: admin