题
以下 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'
注意:
- 可执行文件的路径在第一个空格处被截断,即使它是单引号的。
- 最后一个路径中的文字“ ”将被转换为制表符。
显然,shell 并没有按照我想要的方式解析引号。我怎样才能避免这些错误?
编辑:“ ”通过两个间接级别进行扩展:第一的, "$p"
(和/或 "$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
)
解决方案
我确实想将 CMD 分配给您,您应该使用
eval $CMD
而不是仅仅 $CMD
在脚本的最后一行。这应该可以解决路径中空格的问题,我不知道如何处理“ ”问题。
其他提示
- 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[@]}"
将 $CMD 中的最后一行替换为
葡萄酒“$EXEC”$ARGS
您会注意到错误是“/home/chris/.wine/drive_c/Program”而不是“/home/chris/.wine/drive_c/Program”
单引号未正确插入,并且字符串被空格分隔。
您可以尝试在空格前面加上 \ ,如下所示:
/home/chris/.wine/drive_c/Program Files/Microsoft\ Research/Z3-1.3.6/bin/z3.exe
您也可以对 问题执行相同的操作 - 将其替换为 \ 。
不隶属于 StackOverflow