如何编写一个带有可选输入参数的bash脚本?

Abe*_*Abe 425 bash arguments parameter-passing

我希望我的脚本能够获取可选输入,

例如,目前我的剧本是

#!/bin/bash
somecommand foo
Run Code Online (Sandbox Code Playgroud)

但我想说:

#!/bin/bash
somecommand  [ if $1 exists, $1, else, foo ]
Run Code Online (Sandbox Code Playgroud)

小智 636

您可以使用default-value语法:

somecommand ${1:-foo}
Run Code Online (Sandbox Code Playgroud)

以上将如Bash参考手册中所述 - 3.5.3 Shell参数扩展 [强调我的]:

如果参数未设置或为null,则替换单词的扩展.否则,参数的值将被替换.

如果您只想在未设置参数时替换默认值(但如果它为空,则不是,例如,如果它是空字符串则不是),请使用以下语法:

somecommand ${1-foo}
Run Code Online (Sandbox Code Playgroud)

再次从Bash参考手册 - 3.5.3 Shell参数扩展:

省略冒号只会导致对未设置的参数进行测试.换句话说,如果包含冒号,运算符将测试参数的存在性及其值不为空; 如果省略冒号,则运算符仅测试是否存在.

  • 请注意上面命令之间的语义差异,"返回`foo`如果`$ 1`未设置*或空字符串*",并且`$ {1-foo}`,"返回`foo`如果`$ 1`未设置". (50认同)
  • 你能解释一下为什么会这样吗?特别是,':'和' - '的功能/目的是什么? (12认同)
  • @jwein001:在上面提交的答案中,如果变量未定义,则使用替换运算符返回默认值.具体来说,逻辑是"如果$ 1存在且不为null,则返回其值;否则,返回foo." 冒号是可选的.如果省略,则将"exists and not null"更改为"exists".减号指定返回foo而不将$ 1设置为等于'foo'.替代运营商是扩张运营商的子类.参见Robbins和Beebe*Classic Shell Scripting*的第6.1.2.1节[O'Reilly](http://shop.oreilly.com/product/9780596005955.do) (8认同)
  • @Jubbles或者如果您不想购买整本书以供简单参考... http://www.tldp.org/LDP/abs/html/parameter-substitution.html (4认同)
  • 如果它显示了如何使默认值成为运行命令的结果(如@hagen一样),则此答案会更好(尽管答案不佳)。 (2认同)

Bra*_*rks 260

您可以为变量设置默认值,如下所示:

somecommand.sh

#!/usr/bin/env bash

ARG1=${1:-foo}
ARG2=${2:-bar}
ARG3=${3:-1}
ARG4=${4:-$(date)}

echo "$ARG1"
echo "$ARG2"
echo "$ARG3"
echo "$ARG4"
Run Code Online (Sandbox Code Playgroud)

以下是一些如何工作的示例:

$ ./somecommand.sh
foo
bar
1
Thu Mar 29 10:03:20 ADT 2018

$ ./somecommand.sh ez
ez
bar
1
Thu Mar 29 10:03:40 ADT 2018

$ ./somecommand.sh able was i
able
was
i
Thu Mar 29 10:03:54 ADT 2018

$ ./somecommand.sh "able was i"
able was i
bar
1
Thu Mar 29 10:04:01 ADT 2018

$ ./somecommand.sh "able was i" super
able was i
super
1
Thu Mar 29 10:04:10 ADT 2018

$ ./somecommand.sh "" "super duper"
foo
super duper
1
Thu Mar 29 10:05:04 ADT 2018

$ ./somecommand.sh "" "super duper" hi you
foo
super duper
hi
you
Run Code Online (Sandbox Code Playgroud)

  • 喔好吧。`-` 让我很困惑(它是否被否定了?)。 (3认同)
  • 不 - 这只是bash做作业的一种奇怪方式.我将添加一些例子来澄清这一点......谢谢! (2认同)

Iri*_*iel 43

if [ ! -z $1 ] 
then 
    : # $1 was given
else
    : # $1 was not given
fi
Run Code Online (Sandbox Code Playgroud)

  • `-n`与`相同!-z`. (17认同)
  • 因为您未能引用该变量,`[ -n $1 ]` *将始终为 true*。如果您使用 bash,`[[ -n $1 ]]` 将按照您的预期运行,否则您必须引用 `[ -n "$1" ]` (6认同)
  • 对于像我这样的人:忘记代码中的“:”,它不是必需的,用你真正的命令替换它! (3认同)
  • 从技术上讲,如果您传入一个空字符串 '' ,它可能会被视为参数,但您的检查将错过它。在这种情况下 $# 会说明给出了多少个参数 (2认同)

Den*_*nis 20

您可以检查参数的数量 $#

#!/bin/bash
if [ $# -ge 1 ]
then
    $1
else
    foo
fi
Run Code Online (Sandbox Code Playgroud)


小智 9

请不要忘记,如果它的变量$ 1 .. $ n你需要写一个常规变量来使用替换

#!/bin/bash
NOW=$1
echo  ${NOW:-$(date +"%Y-%m-%d")}
Run Code Online (Sandbox Code Playgroud)

  • Brad的[回答](http://stackoverflow.com/a/33419280/603516)证明了参数变量也可以在没有中间变量的情况下被替换. (2认同)
  • +1表示使用日期等命令(默认值)而不是固定值的方式。这也有可能:`DAY = $ {1:-$(date +%F -d“ yesterday”)}` (2认同)

Jes*_*ick 6

对于可选的多个参数,类似于ls可以接受一个或多个文件的命令,或者默认列出当前目录中的所有内容:

if [ $# -ge 1 ]
then
    files="$@"
else
    files=*
fi
for f in $files
do
    echo "found $f"
done
Run Code Online (Sandbox Code Playgroud)

唉,对于路径中带有空格的文件无法正常工作。还没有弄清楚如何使其发挥作用。


Gar*_*n S 5

可以使用变量替换来替换date参数的固定值或命令(如 )。到目前为止,答案都集中在固定值上,但这就是我用来使日期成为可选参数的方法:

~$ sh co.sh
2017-01-05

~$ sh co.sh 2017-01-04
2017-01-04

~$ cat co.sh

DAY=${1:-$(date +%F -d "yesterday")}
echo $DAY
Run Code Online (Sandbox Code Playgroud)


mos*_*osh 5

这允许可选的第一个参数的默认值,并保留多个参数。

 > cat mosh.sh
   set -- ${1:-xyz} ${@:2:$#} ; echo $*    
 > mosh.sh
   xyz
 > mosh.sh  1 2 3
   1 2 3 
Run Code Online (Sandbox Code Playgroud)