在Shell脚本中引用命令行参数
时间:2020-03-05 18:45:29 来源:igfitidea点击:
以下shell脚本采用参数列表,将Unix路径转换为WINE / Windows路径,并在WINE下调用给定的可执行文件。
#! /bin/sh if [ "${1+set}" != "set" ] then echo "Usage; winewrap EXEC [ARGS...]" exit 1 fi EXEC="" 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'
注意:
- 可执行文件的路径在第一个空格处被切断,即使它是单引号也是如此。
- 最后一条路径中的文字" \ t"正在转换为制表符。
显然,引号并没有按照我希望的方式进行解析。如何避免这些错误?
编辑:" \ 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,或者任何操作数包含反斜杠('')字符,则结果是实现定义的。" (" echo"的POSIX规范)
解决方案
回答
我们可以尝试使用\开头空格,如下所示:
/home/chris/.wine/drive_c/Program Files/Microsoft\ Research/Z3-1.3.6/bin/z3.exe
我们也可以对\ t问题进行相同的处理,而将其替换为\ t。
回答
将$ CMD的最后一行替换为
葡萄酒'$ EXEC'$ ARGS
我们会注意到错误是" /home/chris/.wine/drive_c/Program"而不是" /home/chris/.wine/drive_c/Program"
单引号未正确插入,并且字符串被空格分隔。
回答
我确实要分配应该使用的CMD
评估$ CMD
而不是脚本最后一行中的$ CMD。这应该用路径中的空格解决问题,我不知道该怎么处理" \ t"问题。
回答
- bashs数组是不可移植的,但是在shell中处理参数列表的唯一明智的方法
- 参数数量以$ {#}为单位
- 如果当前目录中的文件名以破折号开头,则脚本将发生错误的情况
- 如果脚本的最后一行仅运行一个程序,并且退出时没有陷阱,则应执行它
考虑到这一点
#! /bin/bash # push ARRAY arg1 arg2 ... # adds arg1, arg2, ... to the end of ARRAY function push() { local ARRAY_NAME="" shift for ARG in "${@}"; do eval "${ARRAY_NAME}[${#${ARRAY_NAME}[@]}]=${ARG}" done } PROG="$(basename -- "##代码##")" 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=("") shift for p in "${@}"; do if [ -e "${p}" ]; then p="$(winepath -w -- "${p}")" fi push EXEC "${p}" done exec "${EXEC[@]}"