我有一个围绕批量运行 SAS 代码的run_sas.sh
命令的包装器。sas
典型的调用如下所示
./run_sas.sh -sysin /my_code/my_program.sas -log /my_log_folder/my_program.log
run_sas.sh
将所有参数传递给sas
with./sas $*
。sas
然后运行/my_code/my_program.sas
并将日志写入/my_log_folder/my_program.log
。- 然后
run_sas.sh
分析调用它的参数 - 并将日志复制到
/admin/.hidden_log_folder/my_program_<today's date>.log
我想做两个改变:
启用多字参数
有些客户绝对希望我在文件夹和文件名中使用空格并要求我运行/their code/their program.sas
,所以如果我运行
./run_sas.sh -sysin "/their code/their program.sas" -log "/their log folder"
/their code/their program.sas
并且/their log folder
应该将单个参数传递给sas
删除特定参数
有时我需要运行./sas_utf8
而不是./sas
,我懒得维护第二个脚本,所以我想允许一个额外的参数,这样
./run_sas.sh -sysin /my_code/my_program.sas -log /my_log_folder -encoding utf8
会打电话
./sas_utf8 -sysin /my_code/my_program.sas -log /my_log_folder
代替
./sas -sysin /my_code/my_program.sas -log /my_log_folder
我怎样才能做到这一点,最好是在ksh
?
答案1
首先,使用"$@"
not $*
(或$@
) 来保持参数完整。它将每个参数扩展为一个单独的单词,就像您使用"$1" "$2"...
Note that with $*
, glob 字符也会是一个问题。
要查找 utf8 选项,您可以循环命令行参数,并将要保留的参数复制到另一个数组,如果看到-encoding
和 则设置一个标志utf8
。
然后只需检查标志变量即可确定要运行哪个程序,并传递"${sasArgs[@]}"
给命令。
所以:
executable="./sas" # The default, for latin encoding
# Inspect the arguments,
# Remember where the log is written
# Change the executable if the encoding is specified
# Copy all arguments except the encoding to the 'sasArgs' array
while [[ "$#" -gt 0 ]]; do
case "$1" in
-encoding)
# change the executable, but do not append to sasArgs
if [[ "$2" = "utf8" ]]; then
executable="./sas_u8"
shift 2
continue
else
echo "The only alternative encoding already supported is utf8" >&2
exit 1
fi
;;
-log)
# remember the next argument to copy the log from
logPath="$2"
;;
esac
sasArgs+=("$1")
shift
done
# To debug: print the args, enclosed in "<>" to discover multi word arguments
printf "Command and args: "
printf "<%s> " "$cmd" "${sasArgs[@]}"
printf "\n"
# exit # when debugging
# Actually run it
"$executable" "${sasArgs[@]}"
# Copy the log using $logPath
# ...
最后的printf
调用打印它将运行的参数,<>
每个参数周围都有,这样您就可以检查带有空格的参数是否保持不变。 (您可以运行echo "${sasArgs[@]}"
,但它无法区分两个参数foo
和bar
, 与单个参数foo bar
。)
如果我们正在寻找单个参数,而不是两个参数对,则第一部分可以通过循环变得更简单for
:
for arg in "$@" do
case "$arg" in
-encoding-utf8)
# change the executable, but do not append to the array
executable="./sas_u8"
continue
;;
esac
sasArgs+=("$arg")
done
这也可以转换为普通的 POSIX sh。该for
循环生成给定列表的副本,因此复制的参数可以存储回位置参数(附加set -- "$@" "$arg"
),而不是使用数组。
此外,如果知道编码参数在一开始,整个交易就会变得简单得多。然后检查$1
( 和)就足够了$2
,并且可以使用 删除它们shift
。
(我用 Bash 和 Debian 上的 ksh93 版本测试了上述脚本。我对 ksh 不太熟悉,所以我可能错过了一些东西。但是 Bash 的数组是从 ksh 复制的,所以我希望它应该可以正常工作同时。)