在shell脚本中引用命令行参数

时间:2008-08-30 16:39:43

标签: unix shell 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

但是,命令行参数的引用有问题。

$ 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. 最后一个路径中的文字“\ t”正在转换为制表符。
  3. 显然,引用没有按照shell的意图解析。我该如何避免这些错误?

    编辑:“\ t”正在通过两个间接级别进行扩展:首先,"$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 specification of echo

4 个答案:

答案 0 :(得分:3)

  • 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[@]}"

答案 1 :(得分:1)

我确实想要使用

来分配给CMD

eval $CMD

而不仅仅是脚本最后一行的$CMD。这应该可以解决路径中空格的问题,我不知道如何处理“\ t”问题。

答案 2 :(得分:0)

您可以尝试在空格前面加上\ like:

/home/chris/.wine/drive_c/Program Files/Microsoft\ Research/Z3-1.3.6/bin/z3.exe

你也可以对你的问题做同样的事情 - 用\\ t替换它。

答案 3 :(得分:0)

将最后一行从$ CMD替换为

wine'$ EXEC'$ ARGS

你会注意到错误是'/home/chris/.wine/drive_c/Program'而不是'/home/chris/.wine/drive_c/Program'

单引号未正确插值,字符串按空格分割。