以下 shell 脚本采用参数列表,将 Unix 路径转换为 ??WINE/Windows 路径并调用 WINE 下的给定可执行文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #! /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 |
但是,命令行参数的引用有问题。
1 2 3
| $ 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' |
请注意:
可执行文件的路径在第一个空格处被截断,即使它是单引号。
最后一个路径中的文字"\\\\t"正在转换为制表符。
显然,shell 并没有按照我想要的方式解析引号。如何避免这些错误?
编辑:"\\\\t"正在通过两个间接级别进行扩展:首先,"$p"(和/或 "$ARGS")正在扩展为 Z:\\tmp\\smtlib3cee8b.smt;然后, \\t 被扩展为制表符。这(似乎)等同于
1 2 3
| Y='y\\ty'
Z="z${Y}z"
echo $Z |
产生
而不是
更新: eval"$CMD" 可以解决问题。"\\t" 问题似乎是 echo 的错误:"如果第一个操作数是 -n,或者任何操作数包含反斜杠 ('\\\\') 字符,则结果是实现定义的。" (echo 的 POSIX 规范)
-
bash 的数组是不可移植的,但却是在 shell 中处理参数列表的唯一明智的方法
-
参数的数量在 ${#}
-
如果当前目录中存在以破折号开头的文件名,您的脚本会出现问题
-
如果脚本的最后一行只是运行一个程序,并且退出时没有陷阱,则应该执行它
考虑到这一点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #! /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[@]}" |
我确实想要分配给 CMD 你应该使用
eval $CMD
而不是 $CMD 在脚本的最后一行。这应该可以解决路径中的空格问题,我不知道该怎么处理 "\\\\\\\\t" 问题。
将 $CMD 的最后一行替换为 just
葡萄酒\\'$EXEC\\'$ARGS
您会注意到错误是 \\'\\'/home/chris/.wine/drive_c/Program\\' 而不是 \\'/home/chris/.wine/drive_c/Program\\'
单引号没有正确插入,字符串被空格分割。
您可以尝试使用 \\\\\\\\ 在空格之前,如下所示:
1
| /home/chris/.wine/drive_c/Program Files/Microsoft\\ Research/Z3-1.3.6/bin/z3.exe |
你也可以对你的 \\\\\\\\t 问题做同样的事情 - 用 \\\\\\\\\\\\\\\\t 替换它。