【问题标题】:How to define a shell script with variable number of arguments?如何定义具有可变数量参数的shell脚本?
【发布时间】:2012-05-05 15:25:36
【问题描述】:

我想定义一个通过 shell 脚本调用 gs (ghostscript) 的简单缩写。第一个参数给出所有应该合并的文件,最后一个给出输出文件的名称。显然,下面的行不通(只是为了显示目标):

#!/bin/sh
gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOUTPUTFILE=$last $1 $2 ...

如何做到这一点?

通常会通过myscript infile1.pdf infile2.pdf ... outfile.pdfmyscript *.pdf outfile.pdf 调用此脚本。

【问题讨论】:

    标签: bash shell


    【解决方案1】:

    bash 变量 $@$* 扩展为命令行参数列表。通常,您会希望使用"$@"(即$@ 用双引号括起来)。如果有人向您的脚本传递一个包含空格的参数,这将做正确的事情。

    如果你的脚本中有这个:

    outputfile=$1
    shift
    gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOUTPUTFILE=$outputfile "$@"
    

    你这样调用你的脚本:

    myscript out.pdf foo.ps bar.ps "another file.ps"
    

    这将扩展为:

    gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOUTPUTFILE=out.pdf foo.ps bar.ps "another file.ps"
    

    阅读bash 手册页的"Special Parameters" 部分了解更多信息。

    【讨论】:

    • 感谢 larsks。是否可以将输出文件名作为 last(不是第一个)参数?
    • Marius Hofert:你不能轻易移开最后一个元素,所以这有点棘手。像这样的东西:outputfile=${@: -1}; args=("${@:1:$((${#@}-1))}")。你应该接受这个 larsks 的回答。
    • 可以,但是有点丑。 Idelic 在他的回答中有一个例子。你的代码最终会变得更加杂乱无章。
    • 嗯.. 我也可以将它与默认变量一起使用吗? echo ${@-'default-val'} 这是我对代码的最佳猜测,但在我测试时它忽略了默认变量。
    • 我需要查看您的实际代码才能回答您的问题(例如,在双引号之外使用 $@ 的任何变体实际上没有意义,但我不知道您是否'是否这样做)。我建议你打开一个新问题,并附上一个你正在尝试做的例子。
    【解决方案2】:

    要将输出文件作为最后一个参数传递,请使用数组:

    ARGS=("$@")
    # Get the last argument
    outputfile=${ARGS[-1]}
    # Drop it from the array
    unset ARGS[${#ARGS[@]}-1]
    
    exec gs ... -sOUTPUTFILE=$outputfile "${ARGS[@]}"
    

    在版本 4 之前,bash 不允许在数组中使用负下标(并产生了 Marius 在 cmets 中报告的错误),因此如果您使用的是 3.x,则需要使用更丑的版本

    outputfile=${ARGS[${#ARGS[@]}-1]}
    

    这也适用于 bash 4.x。

    【讨论】:

    • 我得到:gsMerge infile1.pdf infile2.pdf all.pdf /usr/bin/gsMerge: line 4: ARGS: bad array subscript **** 无法打开初始设备,退出。
    • @Marius:您可能使用的是旧版本的bash。我更新了答案以涵盖该案例。
    • 补充一点:在 Mac OS X 10.10.3 上,我将 bash 更新为 4.3.33,但仍需要使用 outputfile=${ARGS[${#ARGS[@]}-1]} 才能正常工作。在 Debian Linux 中使用 bash 4.3.30 outputfile=${ARGS[-1]} 工作。
    【解决方案3】:

    要访问最后一个参数,除了上面 Idelic 的回答,您还可以这样做:

    echo "${@: $#}"
    

    这会读取所有参数并从最后一个开始打印它们。这样,您还可以访问最后 N 个参数,例如最后三个参数:

    echo "${@: $#-2}"
    
    $ ./script "what    does" "this  script" "do" "?"
    this  script do ?
    

    【讨论】:

    • 哇,这太棒了。这是在手册中定义的?这个有范围版本吗?
    • 查看这个答案:link 关于拼接数组,上面的答案只是使用它来分割输入参数的数组。
    猜你喜欢
    • 2012-05-26
    • 1970-01-01
    • 1970-01-01
    • 2011-12-30
    • 2021-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-13
    相关资源
    最近更新 更多