3

以下 shell 脚本采用参数列表,将 Unix 路径转换为 ​​WINE/Windows 路径,并在 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

但是,命令行参数的引用有问题。

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

注意:

  1. 可执行文件的路径在第一个空格处被截断,即使它是单引号。
  2. 最后一个路径中的文字“\t”正在转换为制表符。

显然,引用并没有按照我预期的方式被 shell 解析。我怎样才能避免这些错误?

编辑: "\t" 正在通过两个间接级别进行扩展:首先,"$p"(and/or "$ARGS") 正在扩展为Z:\tmp\smtlib3cee8b.smt; 然后,\t正在扩展为制表符。这(似乎)相当于

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

产生

zy\tyz

不是

zy  yz

更新:eval "$CMD"成功了。" \t" 问题似乎是 echo 的错误:“如果第一个操作数是 -n,或者任何操作数包含反斜杠 ('\') 字符,则结果是实现定义的。” (POSIX 规范echo

4

4 回答 4

3
  • bash 的数组是不可移植的,但是在 shell 中处理参数列表的唯一明智的方法
  • 参数的数量在 ${#}
  • 如果当前目录中存在以破折号开头的文件名,您的脚本会出现问题
  • 如果脚本的最后一行只是运行一个程序,并且退出时没有陷阱,则应该执行它

考虑到这一点

#! /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[@]}"
于 2008-09-21T23:35:25.980 回答
1

我你确实想要分配给你应该使用的 CMD

eval $CMD

而不仅仅是$CMD在脚本的最后一行。这应该可以解决路径中的空格问题,我不知道如何处理“\t”问题。

于 2008-09-03T16:02:40.363 回答
0

您可以尝试在空格前面加上 \,如下所示:

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

你也可以对你的 \t 问题做同样的事情 - 用 \\t 替换它。

于 2008-08-30T16:42:34.670 回答
0

将 $CMD 的最后一行替换为 just

葡萄酒'$EXEC'$ARGS

您会注意到错误是 ''/home/chris/.wine/drive_c/Program' 而不是 '/home/chris/.wine/drive_c/Program'

单引号未正确插入,字符串被空格分割。

于 2008-08-30T17:37:17.800 回答