Question

Le script shell suivant prend une liste d'arguments, transforme les chemins Unix en chemins WINE/Windows et appelle l'exécutable donné sous 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

Cependant, il y a quelque chose qui ne va pas dans la citation des arguments de ligne de commande.

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

Noter que:

  1. Le chemin d'accès à l'exécutable est coupé au premier espace, même s'il est entre guillemets simples.
  2. Le " " littéral dans le dernier chemin est transformé en caractère de tabulation.

De toute évidence, les citations ne sont pas analysées comme je le souhaitais par le shell.Comment puis-je éviter ces erreurs ?

MODIFIER:Le " " est étendu à travers deux niveaux d'indirection :d'abord, "$p" (et/ou "$ARGS") est en cours d'extension dans Z:\tmp\smtlib3cee8b.smt;alors, \t est développé dans le caractère de tabulation.Ceci est (apparemment) équivalent à

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

ce qui donne

zy\tyz

et pas

zy  yz

MISE À JOUR: eval "$CMD" fait l'affaire.Le "\t" Le problème semble être la faute d'Echo :"Si le premier opérande est -N, ou si l'un des opérandes contienne un caractère bombardement (''), les résultats sont définis par l'implémentation." (Spécification POSIX de echo)

Était-ce utile?

La solution

Si vous voulez avoir l'affectation à CMD, vous devriez utiliser

eval $CMD

au lieu de juste $CMD dans la dernière ligne de votre script.Cela devrait résoudre votre problème avec les espaces dans les chemins, je ne sais pas quoi faire avec le problème " ".

Autres conseils

  • les tableaux de bash ne sont pas portables mais constituent le seul moyen sensé de gérer les listes d'arguments dans le shell
  • Le nombre d'arguments est en ${#}
  • De mauvaises choses se produiront avec votre script s'il y a des noms de fichiers commençant par un tiret dans le répertoire courant
  • Si la dernière ligne de votre script exécute simplement un programme et qu'il n'y a aucun piège à la sortie, vous devez l'exécuter

Dans cet esprit

#! /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[@]}"

remplacez la dernière ligne de $CMD par juste

vin '$EXEC' $ARGS

Vous remarquerez que l'erreur est ''/home/chris/.wine/drive_c/Program' et non '/home/chris/.wine/drive_c/Program'

Les guillemets simples ne sont pas interpolés correctement et la chaîne est divisée par des espaces.

Vous pouvez essayer de faire précéder les espaces de \ comme ceci :

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

Vous pouvez également faire la même chose avec votre problème - remplacez-le par \ .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top