简介
Bash脚本将命令行参数作为输入,既可以按顺序也可以作为选项进行解析。命令行工具使用这些参数来有条件地触发Bash脚本中的功能,或者有选择地选择环境来执行脚本。在Bash中,这些都是以不同的方式配置的。
在这篇文章中,我们将探索几种创建这些参数的方法,以供消费,并演示一个实现命令行参数的实际例子。
位置性的命令行参数
命令行参数是以位置方式读取的,从位置$1, $2, ..$n
。$
后面跟着一个integer
的模式是一个保留组合,用来表示命令行参数。
$0
表示脚本的名称。
下面是一个用于调用脚本的位置性命令行参数的图示。
考虑下面这个脚本,arg_intro.sh
,其中的参数是按照它们的位置打印的。
#!/bin/bash
echo "Script name is: $0"
echo "Arg1 is $1"
echo "Arg1 is $2"
echo "Arg1 is $3"
echo "-----------"
echo "All args: $*"
echo "All args count: $#"
这个shell脚本被执行,参数如下图所示。
$ bash arg_intro.sh runtime inputs
Script name is: ./arg_intro.sh
Arg1 is runtime
Arg1 is inputs
Arg1 is
-----------
All args: runtime inputs
All args count: 2
使用getopt解析复杂参数
在上一节中,你了解了如何将位置参数传入脚本。如果参数的数量增加,或者对变量的赋值有条件要求,这种方法就不太适用了。在这种情况下,需要有一个坚实的框架。
命令行工具getopt
,通过提供语法和选项来定义和解析参数,解决了这个问题。
下面是一个关于如何使用getopt
来定义参数的要点。
定义选项
当把参数传递给一个命令行工具时,有两种类型的参数。这些包括。
- 短参数- 这些参数是由一个字符定义的,前面有一个连字符。例如,
-h
可能表示帮助,-l
可能表示一个列表命令。 - 长参数- 这些是整个字符串,以两个连字符为前缀。例如,
--help
表示帮助,--list
表示列表。
考虑这个脚本test_options.sh
,其中设置参数的工具是getopt
。
#!/bin/bash
SHORT=c:,d:,h
LONG=city1:,city2:,help
OPTS=$(getopt --alternative --name weather --options $SHORT --longoptions $LONG -- "$@")
短参数被传递给getopt
工具的--options
标志,而长参数被传递给--longoptions
标志。在上面的代码中,我们有三个短选项。
c
对应到城市1d
对应城市2h
对应帮助。
命令行实用程序中的help
选项不取任何值,因此它没有冒号连接。
- 单冒号(:)--该选项需要取值
- 双冒号(::)--值是可选的
- 没有冒号--不需要任何值
在上面的代码中,参数c
和d
(后面是冒号)需要发送值,而选项h
不需要任何参数(没有冒号)。
转移到其他参数
getopt
工具将输入的参数放到一个有组织的位置输出。
例如,让我们调整一下test_options.sh
来打印我们的选项。
#!/bin/bash
SHORT=c:,d:,h
LONG=city1:,city2:,help
OPTS=$(getopt -a -n weather --options $SHORT --longoptions $LONG -- "$@")
echo $OPTS
当向这个脚本传递参数时,它的输出结果如下。
$ bash test_options.sh --city1 Paris --city2 NewYork
--city1 'Paris' --city2 'NewYork' --
下面是该脚本生成的输出的可视化表示,以及QA环境的演示。
请注意,该工具已经添加了一个尾部的双连字符(--
),表示输出的结束。现在,这些输出可以被视为位置参数,并写出循环来迭代每个参数。这就是shift
关键字的用处。
shift
关键字需要一个额外的参数,即光标要移动到参数的多少个位置。为了解析下一个参数,shift命令有一个数字2
,它将切换到下一个参数。
考虑一下test_options_looping.sh
脚本,它使用shift
来捕捉和打印我们参数中的选项值。
#!/bin/bash
SHORT=c:,d:,h
LONG=city1:,city2:,help
OPTS=$(getopt -a -n weather --options $SHORT --longoptions $LONG -- "$@")
eval set -- "$OPTS"
while :
do
case "$1" in
-c | --city1 )
city1="$2"
shift 2
;;
-d | --city2 )
city2="$2"
shift 2
;;
-h | --help)
"This is a weather script"
exit 2
;;
--)
shift;
break
;;
*)
echo "Unexpected option: $1"
;;
esac
done
echo $city1, $city2
当该脚本通过有效的参数被调用时,它的结果是将两个被分配的变量打印为。
$ bash test_options_looping.sh --city1 Paris --city2 NewYork
Paris, NewYork
请注意脚本在遇到双连字符时是如何退出的 (--
)。
有了上面的经验,让我们做一个CLI天气应用程序的例子,接受并解析城市名称作为参数。
例子--建立一个命令行天气应用程序
这个命令行天气应用程序从wttr.in[,](wttr.in)一个由Igor Chubin创建的公共和免费的天气网络应用中获取数据。我们的shell脚本用curl
工具发出一个GET
请求,以检索一个天气报告。如果有两个参数被传递,它就会给出两个城市的天气对比。
该脚本包含所有上述的组件,包括getopt
工具的调用。根据输入的参数,会对有效参数的数量进行检查。
如果没有传入参数,help()
函数就会被执行并退出。如果没有,脚本继续进行,并检查开关情况下的选项。
基于输入,if-else
条件被评估,通过用输入替换字符串参数,对URL进行curl
。
让我们创建一个名为weather.sh
的脚本,代码如下。
#!/bin/bash
help()
{
echo "Usage: weather [ -c | --city1 ]
[ -d | --city2 ]
[ -h | --help ]"
exit 2
}
SHORT=c:,d:,h
LONG=city1:,city2:,help
OPTS=$(getopt -a -n weather --options $SHORT --longoptions $LONG -- "$@")
VALID_ARGUMENTS=$# # Returns the count of arguments that are in short or long options
if [ "$VALID_ARGUMENTS" -eq 0 ]; then
help
fi
eval set -- "$OPTS"
while :
do
case "$1" in
-c | --city1 )
city1="$2"
shift 2
;;
-d | --city2 )
city2="$2"
shift 2
;;
-h | --help)
help
;;
--)
shift;
break
;;
*)
echo "Unexpected option: $1"
help
;;
esac
done
if [ "$city1" ] && [ -z "$city2" ]
then
curl -s "https://wttr.in/${city1}"
elif [ -z "$city1" ] && [ "$city2" ]
then
curl -s "https://wttr.in/${city2}"
elif [ "$city1" ] && [ "$city2" ]
then
diff -Naur <(curl -s "https://wttr.in/${city1}" ) <(curl -s "https://wttr.in/${city2}" )
else
curl -s https://wttr.in
fi
该脚本在以下情况下进行测试
**i)**测试案例1 - 当提供一个城市的时候:
$ bash weather.sh -city1 NewYork
**ii)**测试案例2 - 当提供两个城市时:
$ bash weather.sh -city1 NewYork -city2 NewDelhi
**iii)**测试案例3 - 当没有提到任何一个城市参数时:
$ bash weather.sh
正如预期的那样,我们的脚本工作正常,它返回输入城市的天气报告。当没有传递参数时,脚本调用help()
函数来返回支持的参数列表。
总结
在这篇文章中,我们已经介绍了从shell脚本中传递位置性参数和解析复杂的可选参数的基本知识。
我们创建的这个实用程序的例子,是根据我们提供给脚本的参数来调用天气API的。