The following shell script takes a list of arguments, turns Unix paths into WINE/Windows paths and invokes the given executable under WINE.
以下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
However, there's something wrong with the quotation of command-line arguments.
但是,命令行参数的引用有问题。
$ 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'
Note that:
- The path to the executable is being chopped off at the first space, even though it is single-quoted.
- The literal "\t" in the last path is being transformed into a tab character.
可执行文件的路径在第一个空格处被切断,即使它是单引号。
最后一个路径中的文字“\ t”正在转换为制表符。
Obviously, the quotations aren't being parsed the way I intended by the shell. How can I avoid these errors?
显然,引用并没有按照shell的意图进行解析。我该如何避免这些错误?
EDIT: The "\t" is being expanded through two levels of indirection: first, "$p"
(and/or "$ARGS"
) is being expanded into Z:\tmp\smtlib3cee8b.smt
; then, \t
is being expanded into the tab character. This is (seemingly) equivalent to
编辑:“\ t”正在通过两个间接级别进行扩展:首先,“$ p”(和/或“$ ARGS”)正在扩展为Z:\ tmp \ smtlib3cee8b.smt;然后,\ t正在扩展到制表符。这(看似)相当于
Y='y\ty'
Z="z${Y}z"
echo $Z
which yields
zy\tyz
and not
zy yz
UPDATE: eval "$CMD"
does the trick. The "\t
" problem seems to be echo's fault: "If the first operand is -n, or if any of the operands contain a backslash ( '\' ) character, the results are implementation-defined." (POSIX specification of echo
)
更新:eval“$ CMD”可以解决问题。 “\ t”问题似乎是echo的错误:“如果第一个操作数是-n,或者如果任何操作数包含反斜杠('\')字符,则结果是实现定义的。” (回声的POSIX规范)
4 个解决方案
#1
1
I you do want to have the assignment to CMD you should use
我确实想要你应该使用CMD的作业
eval $CMD
instead of just $CMD
in the last line of your script. This should solve your problem with spaces in the paths, I don't know what to do about the "\t" problem.
而不是在脚本的最后一行只有$ CMD。这应该可以解决路径中空格的问题,我不知道如何处理“\ t”问题。
#2
3
- bash’s arrays are unportable but the only sane way to handle argument lists in shell
- The number of arguments is in ${#}
- Bad stuff will happen with your script if there are filenames starting with a dash in the current directory
- If the last line of your script just runs a program, and there are no traps on exit, you should exec it
bash的数组是不可移植的,但是在shell中处理参数列表的唯一理智方式
参数的数量是$ {#}
如果在当前目录中有以破折号开头的文件名,则脚本会发生错误
如果脚本的最后一行只是运行一个程序,并且退出时没有陷阱,那么你应该执行它
With that in mind
考虑到这一点
#! /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[@]}"
#3
0
replace the last line from $CMD to just
将$ CMD中的最后一行替换为just
wine '$EXEC' $ARGS
葡萄酒'$ EXEC'$ ARGS
You'll note that the error is ''/home/chris/.wine/drive_c/Program' and not '/home/chris/.wine/drive_c/Program'
您会注意到错误是'/home/chris/.wine/drive_c/Program'而不是'/home/chris/.wine/drive_c/Program'
The single quotes are not being interpolated properly, and the string is being split by spaces.
单引号没有正确插值,字符串被空格分割。
#4
0
You can try preceeding the spaces with \ like so:
您可以尝试在空格前面加上\ like,如下所示:
/home/chris/.wine/drive_c/Program Files/Microsoft\ Research/Z3-1.3.6/bin/z3.exe
You can also do the same with your \t problem - replace it with \\t.
你也可以对你的问题做同样的事情 - 用\\ t替换它。
#1
1
I you do want to have the assignment to CMD you should use
我确实想要你应该使用CMD的作业
eval $CMD
instead of just $CMD
in the last line of your script. This should solve your problem with spaces in the paths, I don't know what to do about the "\t" problem.
而不是在脚本的最后一行只有$ CMD。这应该可以解决路径中空格的问题,我不知道如何处理“\ t”问题。
#2
3
- bash’s arrays are unportable but the only sane way to handle argument lists in shell
- The number of arguments is in ${#}
- Bad stuff will happen with your script if there are filenames starting with a dash in the current directory
- If the last line of your script just runs a program, and there are no traps on exit, you should exec it
bash的数组是不可移植的,但是在shell中处理参数列表的唯一理智方式
参数的数量是$ {#}
如果在当前目录中有以破折号开头的文件名,则脚本会发生错误
如果脚本的最后一行只是运行一个程序,并且退出时没有陷阱,那么你应该执行它
With that in mind
考虑到这一点
#! /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[@]}"
#3
0
replace the last line from $CMD to just
将$ CMD中的最后一行替换为just
wine '$EXEC' $ARGS
葡萄酒'$ EXEC'$ ARGS
You'll note that the error is ''/home/chris/.wine/drive_c/Program' and not '/home/chris/.wine/drive_c/Program'
您会注意到错误是'/home/chris/.wine/drive_c/Program'而不是'/home/chris/.wine/drive_c/Program'
The single quotes are not being interpolated properly, and the string is being split by spaces.
单引号没有正确插值,字符串被空格分割。
#4
0
You can try preceeding the spaces with \ like so:
您可以尝试在空格前面加上\ like,如下所示:
/home/chris/.wine/drive_c/Program Files/Microsoft\ Research/Z3-1.3.6/bin/z3.exe
You can also do the same with your \t problem - replace it with \\t.
你也可以对你的问题做同样的事情 - 用\\ t替换它。