質問
次のシェル スクリプトは引数のリストを受け取り、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'
ご了承ください:
- 実行可能ファイルへのパスは、一重引用符で囲まれているにもかかわらず、最初のスペースで切り取られます。
- 最後のパスのリテラル「 」はタブ文字に変換されます。
明らかに、引用符はシェルによって意図した方法で解析されていません。これらのエラーを回避するにはどうすればよいでしょうか?
編集:「 」は 2 つのレベルの間接化によって展開されます。初め、 "$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 の配列は移植性がありませんが、シェルで引数リストを処理する唯一のまともな方法です
- 引数の数は ${#} にあります
- 現在のディレクトリにダッシュで始まるファイル名がある場合、スクリプトで問題が発生します。
- スクリプトの最後の行がプログラムを実行するだけで、終了時にトラップがない場合は、それを実行する必要があります。
それを念頭に置いて
#! /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
問題についても同じことを行うことができます。\ に置き換えます。