質問

次のシェル スクリプトは引数のリストを受け取り、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. 最後のパスのリテラル「 」はタブ文字に変換されます。

明らかに、引用符はシェルによって意図した方法で解析されていません。これらのエラーを回避するにはどうすればよいでしょうか?

編集:「 」は 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

問題についても同じことを行うことができます。\ に置き換えます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top