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

How to write a bash script that takes optional input arguments?

提问人:Abe 提问时间:2/18/2012 最后编辑:AmirAbe 更新时间:8/21/2023 访问量:457810

问:

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

例如,目前我的脚本是

#!/bin/bash
somecommand foo

但我想说:

#!/bin/bash
somecommand  [ if $1 exists, $1, else, foo ]
bash 参数传递

评论

3赞 Vadzim 3/28/2016
另请参阅 unix.stackexchange.com/questions/122845/...
2赞 Vadzim 3/28/2016
...stackoverflow.com/questions/2013547/......
0赞 Joonho Park 2/16/2021
我想说的是,这个主题不是关于可选参数,而是关于具有默认值的位置参数。这个术语给人很多混淆。“可选参数”意味着无论这些参数是否存在于命令行中都可以。

答:

66赞 Irit Katriel 2/18/2012 #1
if [ ! -z $1 ] 
then 
    : # $1 was given
else
    : # $1 was not given
fi

评论

2赞 vmpstr 2/18/2012
从技术上讲,如果您传入一个空字符串 '',它可能算作参数,但您的检查会错过它。在这种情况下,$# 会说出给定了多少个参数
30赞 l0b0 2/21/2012
-n与 相同。! -z
1赞 Eliezer 12/20/2019
我使用得到不同的结果,所以我想说这里不是这种情况。-n! -z
6赞 glenn jackman 3/19/2020
因为您没有引用变量,所以将始终为 true。如果你使用 bash,将按照你的期望行事,否则你必须引用[ -n $1 ][[ -n $1 ]][ -n "$1" ]
3赞 Anh-Thi DINH 11/12/2021
对于像我这样的人:忘记代码中的“:”,这不是必需的,用你的真实命令替换它!
32赞 Dennis 2/18/2012 #2

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

#!/bin/bash
if [ $# -ge 1 ]
then
    $1
else
    foo
fi
1065赞 Itay Perl 2/18/2012 #3

您可以使用默认值语法:

somecommand ${1:-foo}

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

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

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

somecommand ${1-foo}

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

省略冒号将导致仅对未设置的参数进行测试。换句话说,如果包含冒号,运算符将测试这两个参数是否存在,并且其值是否为空;如果省略冒号,则操作员仅测试是否存在。

评论

77赞 l0b0 2/21/2012
请注意上述命令“return if is unset or an empty string”和“return if is unset”之间的语义差异。foo$1${1-foo}foo$1
17赞 jwien001 9/6/2014
你能解释一下为什么这样做吗?特别是,“:”和“-”的功能/目的是什么?
11赞 Jubbles 9/24/2014
@jwein001:在上面提交的答案中,如果变量未定义,则使用替换运算符返回默认值。具体来说,逻辑是“如果 $1 存在且不为 null,则返回其值;否则,返回 foo。冒号是可选的。如果省略,请将“exists and isn't null”更改为仅“exists”。减号指定返回 foo,而不将 $1 设置为等于 'foo'。替换运算符是扩展运算符的一个子类。参见 Robbins and Beebe 的经典 Shell 脚本 [O'Reilly] (shop.oreilly.com/product/9780596005955.do 的第 6.1.2.1 节)
6赞 Ohad Schneider 2/8/2017
@Jubbles或者,如果您不想购买一整本书作为简单的参考......tldp.org/LDP/abs/html/parameter-substitution.html
3赞 sautedman 3/18/2017
如果它显示了如何使默认值成为运行命令的结果,那么这个答案会更好,就像@hagen所做的那样(尽管这个答案是不优雅的)。
12赞 hagen 5/26/2015 #4

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

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

评论

2赞 Vadzim 3/28/2016
Brad 上面的回答证明,参数变量也可以在没有中间变量的情况下替换。
2赞 Garren S 1/7/2017
+1 表示使用命令(如 date)作为默认值而不是固定值的方法。这也是可能的:DAY=${1:-$(date +%F -d "yesterday")}
538赞 Brad Parks 10/30/2015 #5

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

somecommand.sh

#!/usr/bin/env bash

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

echo "$ARG1"
echo "$ARG2"
echo "$ARG3"
echo "$ARG4"

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

$ ./somecommand.sh
foo
bar is
1
Thu 19 May 2022 06:58:52 ADT

$ ./somecommand.sh ez
ez
bar is
1
Thu 19 May 2022 06:58:52 ADT

$ ./somecommand.sh able was i
able
was
i
Thu 19 May 2022 06:58:52 ADT

$ ./somecommand.sh "able was i"
able was i
bar is
1
Thu 19 May 2022 06:58:52 ADT

$ ./somecommand.sh "able was i" super
able was i
super
1
Thu 19 May 2022 06:58:52 ADT

$ ./somecommand.sh "" "super duper"
foo
super duper
1
Thu 19 May 2022 06:58:52 ADT

$ ./somecommand.sh "" "super duper" hi you
foo
super duper
hi
you

评论

8赞 Raffi Khatchadourian 3/29/2018
啊,好吧。困惑的我(是否定的?-
16赞 Brad Parks 3/29/2018
不 - 这只是 bash 完成任务的一种奇怪方式。我将添加更多示例来澄清这一点......谢谢!
0赞 Joonho Park 2/17/2022
看起来这是 bash 参数的极限。使用 python 术语,这不是可选的,而是位置性的。它只是一个具有默认值的位置参数。bash 中没有真正的可选参数吗?
0赞 Brad Parks 2/17/2022
你也许可以使用 getopts 来获得你想要的东西 - 这里有 2 个 stackoverflow 答案,它们更详细地介绍了: dfeault 值函数内部
0赞 mirekphd 5/19/2022
另请注意,为了更加混淆(使用 JSON/python 字典),任何地方都不允许有空格,例如在冒号之后和/或破折号之后/之前......这里的最小惊讶原则在哪里?:)
5赞 Jesse Glick 6/9/2016 #6

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

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

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

4赞 Garren S 1/7/2017 #7

可以使用变量替换来替换固定值或命令(如 )来替换参数。到目前为止,答案都集中在固定值上,但这是我用来使日期成为可选参数的方法: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
9赞 mosh 11/26/2017 #8

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

 > cat mosh.sh
   set -- ${1:-xyz} ${@:2:$#} ; echo $*    
 > mosh.sh
   xyz
 > mosh.sh  1 2 3
   1 2 3 
-1赞 Emmanuel de Carvalho Garcia 9/22/2022 #9

当你使用 ${1: } 时,你可以捕获传递给函数的第一个参数 (1),或者 (:) 你可以捕获一个空格,就像默认值一样。

例如。为了能够使用 Laravel artisan,我将其放入我的 .bash_aliases 文件中:

artisan() {
    docker exec -it **container_name** php artisan ${1: } ${2: } ${3: } ${4: } ${5: } ${6: } ${7: }
}  

现在,我只需输入命令行:

  • artisan -- 所有参数(${1: } ${2: } ${3: } ${4: } ${5: } ${6: } ${7: }) 将只是空格
  • Artisan cache:clear -- 第一个参数 ( ${1: } ) 将是 cache:clear,所有其他参数都只是空格

因此,在这种情况下,我可以选择传递 7 个参数。

我希望它可以帮助某人。

1赞 Kiran Kumar 7/11/2023 #10
while getopts a: flag
do
    case "$flag" in
        a) arg1=${OPTARG};;
    esac
done

echo "Print optional argument: $arg1"

if [[ -z "$arg1" ]]; then
    ARG=DEFAULT_VAL
else
    ARG=$arg1
fi  

#Run using below command (eg: file name : runscript.sh)
bash runscript.sh -a argument_val &