Pergunta

O script de shell a seguir pega uma lista de argumentos, transforma caminhos Unix em caminhos WINE/Windows e invoca o executável fornecido em 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

No entanto, há algo errado com a citação de argumentos de linha de 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'

Observe que:

  1. O caminho para o executável está sendo cortado no primeiro espaço, mesmo que esteja entre aspas simples.
  2. O literal " " no último caminho está sendo transformado em um caractere de tabulação.

Obviamente, as citações não estão sendo analisadas da maneira pretendida pelo shell.Como posso evitar esses erros?

EDITAR:O " " está sendo expandido através de dois níveis de indireção:primeiro, "$p" (e/ou "$ARGS") está sendo expandido para Z:\tmp\smtlib3cee8b.smt;então, \t está sendo expandido para o caractere de tabulação.Isto é (aparentemente) equivalente a

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

que rende

zy\tyz

e não

zy  yz

ATUALIZAR: eval "$CMD" faz o truque.O "\t"O problema parece ser culpa do echo:"Se o primeiro operando for -n, ou se algum dos operandos contiver um caractere de barragem (''), os resultados serão definidos pela implementação." (Especificação POSIX de echo)

Foi útil?

Solução

Se você quiser ter a atribuição ao CMD, você deve usar

eval $CMD

em vez de apenas $CMD na última linha do seu script.Isso deve resolver seu problema com espaços nos caminhos, não sei o que fazer com o problema " ".

Outras dicas

  • Os arrays do bash não são portáveis, mas a única maneira sensata de lidar com listas de argumentos no shell
  • O número de argumentos está em ${#}
  • Coisas ruins acontecerão com o seu script se houver nomes de arquivos começando com um travessão no diretório atual
  • Se a última linha do seu script apenas executa um programa e não há armadilhas na saída, você deve executá-lo

Com aquilo em 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[@]}"

substitua a última linha de $CMD por apenas

vinho '$EXEC' $ARGS

Você notará que o erro é ''/home/chris/.wine/drive_c/Program' e não '/home/chris/.wine/drive_c/Program'

As aspas simples não estão sendo interpoladas corretamente e a string está sendo dividida por espaços.

Você pode tentar preceder os espaços com \ assim:

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

Você também pode fazer o mesmo com o seu problema - substituí-lo por \ .

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top