从 shell 脚本调用命令,传递大多数参数,允许带空格的参数

从 shell 脚本调用命令,传递大多数参数,允许带空格的参数

我有一个围绕批量运行 SAS 代码的run_sas.sh命令的包装器。sas典型的调用如下所示

./run_sas.sh -sysin /my_code/my_program.sas -log /my_log_folder/my_program.log
  • run_sas.sh将所有参数传递给saswith ./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[@]}",但它无法区分两个参数foobar, 与单个参数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 复制的,所以我希望它应该可以正常工作同时。)

相关内容