Linux#8 Shell的人机交互-输入篇

碎片时间x体系学习

这是第144篇原创;距2019年还有173天

00

Shell的人机输入交互

命令行参数:填在命令后的数据值,为命令提供运行参数

命令行选项:命令后的、跟在破折线后面的单个字母,可以改变命令的行为

键盘输入:用户通过键盘键入单个或多个参数值并赋值给shell变量

01

命令行参数

命令行参数是向shell脚本传递数据最基本方法。命令行参数在运行脚本时向命令行添加数据值:

$./commandvar1var2var3

在上例中,启动了shell脚本command,并向该脚本传递了3个命令行参数—var1、var2与var3。下面我们将对shell脚本如何处理命令行参数进行说明。

1.1 读取参数

shell变量通过位置参数的特殊变量对命令行参数进行解析。其规则非常简单,具体使用方法示例见下图:

$0:shell在命令行启动的程序的名称

$1 ~ $9:第1 ~ 第9个参数

$ ~ $:分别表示第10 ~ 第N个参数(N>10)

$#:命令行参数的个数(并不包括启动程序的名称参数)

$*:将命令行上提供的所有参数当做单个单词保存;也就是说,$*变量会将这些参数当做一个参数,而不是多个对象;不支持for命令

$@:将命令行上提供的所有参数当做一个字符串保存;但是,它允许你通过for命令遍历所有的值,将提供的每个参数分割开。

注意事项:

当命令行参数值包括空格时,记得需要将该包括空格在内的参数值用单引号或双引号圈起来(将文本字符串作为参数传递时,引号并不是数据的一部分。它们只是将数据的开始、结尾和其他内容分开)

如果脚本的命令行的参数个数超过9,那么在第9个变量之后,需要用花括号将数字包裹起来;如:$1表示第一个变量参数;第11个变量参数则用$进行标识

$0可能是命令名称,也可能是包括该命令在内的全路径名称。为了能够获取命令的名称,可用basename $0命令进行统一处理,无论采用何种方式启动程序,均可正确获取命令名称

当我们判断某个参数是否有数据内容时,可以用if [ -n $var ]进行判断;如果参数存在则继续进行处理,否则执行退出或赋值变量默认值

如果我们使用for命令遍历$*、$@两个特殊变量,可以发现:$*变量会将所有命令行参数当成了单个参数;而$@变量会单独处理每个参数,这是遍历获取所有参数值的最佳实践

1.2 移动变量

bash shell工具链中提供了shift命令来帮助操作命令行参数,该命令会根据它们的相对位置来移动命令行参数,实现对命令行参数的遍历。

使用shift命令时,默认情况下它会将每个参数变量减一。比如命令行有3个参数,当执行shift命令一次后,变量$3的值会移动到$2,变量$2的值会移动到$1,而变量$1的值则会被删除。

当我们不知道命令行参数个数的情况下,采用shift命令遍历其命令行参数是一种绝佳的方法。我们可以只操作第一个参数,执行shif命令移动参数,然后继续操作第一个参数,依次迭代。当然,你也可以执行shift n命令,n为你想移动的参数位数,默认为1。

02

命令行选项

所谓命令行选项,是紧跟在破折号后面的单个字母,能改变命令的行为。

2.1 基本处理方法

一般实际shell应用中,参数与选项会同时出现在命令行中,那么我们一般需要对其参数与选项的进行分离处理。处理方法也很简单,基于while+case的组合控制命令即可,如下例所示:

该例提供了对于命令行参数与选项的基本处理方法,提供了以下功能:

通过while循环+shift的命令组合实现了对命令行选项与参数的遍历

通过case命令实现了对选项的识别,并对于选项带参数、选项不带参数的不同场景做了不同的业务处理;对于选项带参数的方式提供了如何获取参数值的方法

bash shell会用双破折线--来表明选项结束了,示例演示了shell看到双破折线后,脚本会安全地将剩下的命令行参数当做参数而非选项来处理

2.2 使用getopt命令

格式:

getopt optstring options parameters

功能:

getopt命令为解析命令行选项与参数提供了方便且强大的功能。该命令可以接受一系列任意形式的命令行选项和参数,并自动将它们转换成适当的格式。

其中,optstring定义了命令行有效的选项字母 ,还定义了哪些选项字母需要参数值。在每个需要参数值的选项字母后面加一个冒号

下面我们通过getopt命令改造上述的例子:

该例提供了基于getopt解析命令行参数与选项的处理方法,提供了以下功能:

set -- `getopt ab:c "$@"` 指示了命令行合法的选项包括-a、-b、-c;其中-b选项是带参数的,而其他两个选项不需要带参数

当命令行出现了不合法的选项-d时,getopt会报出“illegal option -- d”的错误信息

getopt命令似乎不能处理带空格的参数值,它会把空格当做参数分隔符,而不是根据双引号将“123 456”当做一个参数;如何才能破局?请转向命令getopts

2.3 使用getopts命令

格式:

getopts optstring variable

功能:

每次调用getopts命令,只能处理一个命令行上检测到的参数。处理完所有的参数后,它会退出并返回一个大于0的退出状态码。这种特性非常适合用在解析命令行所有参数的循环中。

与getopt命令类似,optstring定义了命令行有效的选项字母。在每个需要参数值的选项字母后面加一个冒号。要去掉该命令的错误输出,可以在所有的optstring之前加一个冒号。

getopts命令有两个重要的环境变量,在循环处理的过程中经常会用到:

OPTARG:保存当前处理的选项的参数值

OPTIND:保存了参数列表中getopts正在处理的参数的位置

下面我们通过getopts命令改造上述的例子:

03

获得用户输入

上面我们讨论了利用命令行选项和参数的方式获取用户输入,以下我们将讨论交互性更强的一种方式——read命令。read命令从键盘/文件中接收输入,并将接收的数据赋值给一个标准变量。

功能说明:

-p选项:允许直接在read命令行后指定提示符,并将键盘的输入值赋值给提示符后的变量

read命令会为提示符输入的所有数据分配一个变量,也可以支持多个变量。输入的每个数据值都会分配给表中的下一个变量;如果变量表在数据之前用完了,剩下的数据就会分配给最后一个变量

可以在read命令行中不指定变量,会将read收到的任何数据都放进特殊环境变量REPLY中

-t选项:指定read命令等待输入的秒数;当计时器过期后,read命令会返回一个非零退出状态码

-s选项:阻止将传递给read命令的数据回显在显示器上(实际上,数据会显示,只是read命令会将文本颜色设成与背景色一致),多用在密码输入的场景

将文件运行cat命令后的输出,通过管道直接传给含有read命令的while命令,每次循环均能读取一行内容

04

小结

综上,本文对shell提供的三种获取用户数据进行了介绍:命令行参数、命令行选项、键盘/文件输入。

命令行参数允许用户运行脚本时直接从命令行输入数据,脚本通过位置参数来获取命令行参数并将其赋值给变量。

命令行选项是单个字母且前面加个破折线。通过设置不同的选项,从而改变脚本的行为。可通过三种方式处理选项:第一种可采取与处理命令行参数相同的方式,利用位置参数遍历选项,并对不同选项执行不同的动作;第二种是采用getopt命令将命令行选项和参数转化成可以在脚本中处理的标准格式;第三种是采用getopts命令,较之getopt,它支持多个值的参数,以及识别脚本为定义选项的处理。

read命令提供了从脚本用户处获得数据的一种交互方式,支持提问等待、输入赋值多变量、隐藏输入回显、等待输入超时等功能。

在下文中,将会对shell脚本与用户交互方式(输出篇)进行介绍,实现将特定数据定位到特定位置。敬请期待!

One More Thing

推荐1:技术与软技能干货分享

上文1:Linux#6 shell的结构化命令

上文2:Linux#7 shell结构化循环命令进阶

近期,我和活跃在业界的一线技术老司机们共同开通了知识星球,——一个与公众号有别,但又一脉相承的技术圈、认知圈:公众号会一如既往地进行知识分享,知识星球则坚持关注解决问题与动手实践,主要涉及Java后端、Linux、Python、Android等技术领域,问题很广、方法很多、思绪很快,希望我们能够在这里驻足思考、交流、沉淀、提升。

你负责认真,我们负责帮你解决问题,让改变发生;欢迎大家扫码加入我们的星球。期待 2018,在程序猿成长的道路上,共同进化!

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180712B08CE500?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券