2008-08-30 6 views
3

Le script shell suivant prend une liste d'arguments, convertit les chemins Unix en chemins WINE/Windows et appelle l'exécutable donné sous WINE.Citation d'arguments de ligne de commande dans des scripts shell

#! /bin/sh 

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

EXEC="$1" 
shift 

ARGS="" 

for p in "[email protected]"; 
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 un problème avec 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' 

Notez que:

  1. Le chemin vers l'exécutable est en cours trancha au premier espace, même si elle est seule cité.
  2. Le caractère "\ t" dans le dernier chemin est en cours de transformation en un 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?

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

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

qui donne

zy\tyz 

et pas

zy yz 

MISE À JOUR: eval "$CMD" le tour est joué. Le problème "\t" semble être la faute de l'écho: "Si le premier opérande est -n, ou si l'un des opérandes contient une barre oblique inverse ('\'), les résultats sont définis par l'implémentation." (POSIX specification of echo)

Répondre

1

Je vous ne voulez avoir l'affectation à vous CMD devez utiliser

eval $CMD

au lieu de simplement $CMD dans la dernière ligne de votre script. Cela devrait résoudre votre problème avec des espaces dans les chemins, je ne sais pas quoi faire à propos du problème "\ t".

0

Vous pouvez essayer les espaces avec précédant \ 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 \ t - le remplacer par \\ t.

+0

Les deux chemins sont des chemins Unix parfaitement valides * en entrée du script *. Les guillemets simples devraient éliminer le besoin d'espaces d'échappement. Et le "\ t" est automatiquement généré par la commande 'winepath' (il transforme"/tmp "en" Z: \ tmp "). –

0

remplacer la dernière ligne de CMD $ juste

vin ARGS $ '$ EXEC'

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.

3
  • tableaux de bash sont non portable mais la seule façon saine de gérer des listes d'arguments dans la coquille
  • Le nombre d'arguments est en $ {#}
  • choses Bad arrivera avec votre script s'il y a des noms de fichiers commençant par un tableau de bord dans le répertoire courant
  • Si la dernière ligne de votre script exécute uniquement un programme, et il n'y a pas de pièges à la sortie, vous devez exec il

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[@]}" 
+0

Définir "nonportable". Cela ne me dérange pas d'utiliser/bin/bash au lieu de/bin/sh, mais j'hésite à exiger une version récente, quelqu'un a-t-il mis au point une matrice de portabilité de script shell Unix (quelles sont les coquilles sur quelles plates-formes)? –

Questions connexes