Pregunta

El siguiente script de shell toma una lista de argumentos, convierte las rutas de Unix en rutas de WINE/Windows e invoca el ejecutable proporcionado en WINE.

#! /bin/sh

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

EXEC="$1"
shift

ARGS=""

for p in "$@";
do
  if [ -e "$p" ]
  then
    p=$(winepath -w $p)
  fi
  ARGS="$ARGS '$p'"
done

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

Sin embargo, hay algún problema con la cita de los argumentos de la línea de comandos.

$ 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'

Tenga en cuenta que:

  1. La ruta al ejecutable se corta en el primer espacio, aunque esté entre comillas simples.
  2. El literal " " en la última ruta se transforma en un carácter de tabulación.

Obviamente, el shell no está analizando las citas de la manera que yo pretendía.¿Cómo puedo evitar estos errores?

EDITAR:El " " se está expandiendo a través de dos niveles de direccionamiento indirecto:primero, "$p" (y/o "$ARGS") se está ampliando a Z:\tmp\smtlib3cee8b.smt;entonces, \t se está expandiendo al carácter de tabulación.Esto es (aparentemente) equivalente a

Y='y\ty'
Z="z${Y}z"
echo $Z

cuyos rendimientos

zy\tyz

y no

zy  yz

ACTUALIZAR: eval "$CMD" Hace el truco.El "\t"El problema parece ser culpa de Echo:"Si el primer operando es -n, o si alguno de los operandos contiene un carácter de barra de inverso (''), los resultados están definidos por la implementación". (especificación POSIX de echo)

¿Fue útil?

Solución

Si quieres tener la asignación a CMD, debes usar

eval $CMD

en lugar de solo $CMD en la última línea de su guión.Esto debería resolver tu problema con los espacios en las rutas, no sé qué hacer con el problema " ".

Otros consejos

  • Las matrices de bash no son portátiles, pero son la única forma sensata de manejar listas de argumentos en Shell.
  • El número de argumentos está en ${#}
  • Sucederán cosas malas con su script si hay nombres de archivos que comienzan con un guión en el directorio actual
  • Si la última línea de su script simplemente ejecuta un programa y no hay trampas al salir, debe ejecutarlo.

Con eso en mente

#! /bin/bash

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

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
fi

EXEC=("${1}")
shift

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

exec "${EXEC[@]}"

reemplace la última línea de $CMD por solo

vino '$EXEC' $ARGS

Notarás que el error es ''/home/chris/.wine/drive_c/Program' y no '/home/chris/.wine/drive_c/Program'

Las comillas simples no se interpolan correctamente y la cadena se divide por espacios.

Puedes intentar anteponer los espacios con \ así:

/home/chris/.wine/drive_c/Program Files/Microsoft\ Research/Z3-1.3.6/bin/z3.exe

También puedes hacer lo mismo con tu problema : reemplázalo con \ .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top