Domanda

Il seguente script di shell accetta un elenco di argomenti, trasforma i percorsi Unix in percorsi WINE/Windows e richiama l'eseguibile fornito sotto 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

Tuttavia, c'è qualcosa di sbagliato nella citazione degli argomenti della riga di comando.

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

Notare che:

  1. Il percorso dell'eseguibile viene troncato nel primo spazio, anche se è racchiuso tra virgolette singole.
  2. Il valore letterale " " nell'ultimo percorso viene trasformato in un carattere di tabulazione.

Ovviamente, le virgolette non vengono analizzate nel modo previsto dalla shell.Come posso evitare questi errori?

MODIFICARE:La " " viene espansa attraverso due livelli di indiretto:Primo, "$p" (e/o "$ARGS") viene espanso in Z:\tmp\smtlib3cee8b.smt;Poi, \t viene espanso nel carattere di tabulazione.Questo è (apparentemente) equivalente a

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

che cede

zy\tyz

E non

zy  yz

AGGIORNAMENTO: eval "$CMD" fa il trucco.IL "\t" il problema sembra essere colpa di echo:"Se il primo operando è -N o se uno qualsiasi degli operandi contiene un carattere di backslash (''), i risultati sono definiti dall'implementazione." (Specifica POSIX di echo)

È stato utile?

Soluzione

Se vuoi avere l'assegnazione a CMD che dovresti usare

eval $CMD

invece che solo $CMD nell'ultima riga del tuo script.Questo dovrebbe risolvere il tuo problema con gli spazi nei percorsi, non so cosa fare per il problema " ".

Altri suggerimenti

  • gli array di bash non sono portabili ma rappresentano l’unico modo sensato per gestire gli elenchi di argomenti nella shell
  • Il numero di argomenti è in ${#}
  • Se nella directory corrente sono presenti nomi di file che iniziano con un trattino, accadranno cose brutte con il tuo script
  • Se l'ultima riga del tuo script esegue semplicemente un programma e non ci sono trappole all'uscita, dovresti eseguirlo

Con quello in 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[@]}"

sostituisci l'ultima riga da $CMD a just

vino '$EXEC' $ARGS

Noterai che l'errore è ''/home/chris/.wine/drive_c/Program' e non '/home/chris/.wine/drive_c/Program'

Le virgolette singole non vengono interpolate correttamente e la stringa viene divisa in spazi.

Puoi provare a far precedere gli spazi con \ in questo modo:

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

Puoi anche fare lo stesso con il tuo problema : sostituiscilo con \ .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top