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


471

我希望我的脚本能够接受可选输入,

例如目前我的脚本是

#!/bin/bash
somecommand foo

但我想说:

#!/bin/bash
somecommand  [ if $1 exists, $1, else, foo ]

3
Bash或POSIX?使用Bash,还有更多的可能性
user123444555621 2012年

@ Pumbaa80 bash-我已经更新了标签。
安倍


Answers:


705

您可以使用默认值语法:

somecommand ${1:-foo}

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

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

如果您只想在未设置参数的情况下替换默认值(但如果它为null,则不要替换,例如,如果它是一个空字符串,则不要),请改用以下语法:

somecommand ${1-foo}

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

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


52
请注意上面的命令,之间的语义差别“返回foo如果$1未设置或空字符串 ”,以及${1-foo}“返回foo如果$1未设置”。
l0b0 2012年

12
您能解释一下为什么行得通吗?特别地,“:”和“-”的功能/目的是什么?
jwien001 2014年

8
@ jwein001:在上面提交的答案中,如果变量未定义,则使用替换运算符返回默认值。具体来说,逻辑是“如果$ 1存在并且不为null,则返回其值;否则,返回foo”。冒号是可选的。如果省略,请将“存在且不为空”更改为仅“存在”。减号指定不将$ 1等于'foo'而返回foo。替代运算符是扩展运算符的子类。请参阅Robbins和Beebe的经典Shell脚本 [O'Reilly]的6.1.2.1节( shop.oreilly.com/product/9780596005955.do
Jubbles

5
@Jubbles或如果您不想购买整本书作为简单参考... tldp.org/LDP/abs/html/parameter-substitution.html
Ohad Schneider

2
如果它显示了如何使默认值成为运行命令的结果(如@hagen一样),则此答案会更好(尽管答案不佳)。
萨特曼

309

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

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"

以下是一些有关其工作原理的示例:

$ ./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

2
喔好吧。使-我困惑(否定了吗?)。
拉菲·哈查杜安

5
不,这只是bash执行任务的怪异方式。我将添加更多示例以澄清这一点……谢谢!
布拉德·帕克斯

44
if [ ! -z $1 ] 
then 
    : # $1 was given
else
    : # $1 was not given
fi

1
从技术上讲,如果您传递一个空字符串”,该字符串可能算作一个参数,但您的检查将忽略它。在那种情况下,$#会说出给出了多少个参数
vmpstr

18
-n与相同! -z
l0b0 2012年

我使用会得到不同的结果-n! -z所以我要说的不是这种情况。
Eliezer

因为您未能引用变量,所以[ -n $1 ] 将始终为true。如果您使用bash,[[ -n $1 ]]将表现出预期的效果,否则必须引用[ -n "$1" ]
glenn jackman

21

您可以使用以下命令检查参数数量 $#

#!/bin/bash
if [ $# -ge 1 ]
then
    $1
else
    foo
fi

10

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

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

2
上面布拉德的答案证明,参数变量也可以在没有中间变量的情况下被替换。
Vadzim

2
+1表示使用日期等命令(默认值)而不是固定值的方式。这也有可能:DAY=${1:-$(date +%F -d "yesterday")}
Garren S

3

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

if [ $# -ge 1 ]
then
    files="$@"
else
    files=*
fi
for f in $files
do
    echo "found $f"
done

不适用于路径中带有空格的文件。还没有想出如何使之工作。


2

这将为可选的第一个参数提供默认值,并保留多个参数。

 > cat mosh.sh
   set -- ${1:-xyz} ${@:2:$#} ; echo $*    
 > mosh.sh
   xyz
 > mosh.sh  1 2 3
   1 2 3 

1

可以使用变量替换将固定值或命令(如date)替换为参数。到目前为止,答案都集中在固定值上,但这就是我用来使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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.