shell脚本基础巩固(7)

处理用户输入

当编写好一个shell脚本文件,运行的时候,可以在命令后面添加参数,也可以在运行的过程中输入参数来改变程序的行为。

命令行传参

1.位置参数

当我们在运行脚本文件时,会输入脚本文件名,如果后面有参数则加上参数。位置参数变量是标准的数字:$0是脚本文件名,$1第一个参数,$2第二个参数,$3第三个参数,以此类推,直到$9。当参数超过$9个时,需使用花括号,比如:${10},${11},${12}。参数与参数之间用空格分隔,如果参数中含有空格,则需要用引号框起来。所有的参数都可以在脚本中进行获取和使用,值得注意的是,对于获取$0即脚本文件名时,它其实获取的是完整的路径,所以如果想要不包含路径,只获取脚本文件名的话,可以使用basename命令。另外,如果本来应该传参数但是最终去没有参数传入,这时为了避免程序报错,可以使用-n来测试是否有参数传入。

这个脚本里面用到了脚本文件名和11个参数,这里用到了一个if判断,判断是否存在最后一个参数${11},因为如果最后一个参数都存在的话,前面的参数都会存在,以此来判断参数是否足够。如果在启动脚本文件的时候参数没有传完整,运行结果如下:

如果参数都传完整了的话,运行结果如下:

shell中还有一些特殊的变量:

$#包含脚本运行时命令行传入的参数个数(注意这里不包含脚本文件名,是从$1开始算起的),这里发现上面的例子中其实可以用$#来判断参数是否传够。如果要通过这个变量获取最后一个参数的话,则使用${!#},这里有一点需要注意,如果没有参数传入,$#则为0,感觉上${!#}好像没有值与之对应,而实际上这时${!#}返回的却是脚本文件名。

运行结果如下:

$*变量会将命令行上提供的所有参数当作一个单词来保存。

$@变量则将所有参数当作同一字符串中的多个独立的单词,这样可以通过遍历来获取所有的参数值。

运行结果如下:

2.移动参数

这里涉及到的命令是shift。在每使用shift命令一次时,默认情况下会将每个参数(不包含$0位置脚本文件名)向左移动一个位置,而排在$1位置的参数会被删除掉。这个可以用来遍历所有参数,特别是当你不知道有多少个参数的时候。虽然在默认情况下使用shift命令一次只能移动一个位置,但是也可以自己定义每次移动多少个位置,只需要在shift命令后面加一个参数即可,如:shift 3

执行结果如下,由于参数一直在向左移动,所以$1一直在变化,直到获得最后一个参数时间,结束循环。

3.处理选项

当我们在运行脚本文件时,除了在后面跟参数,也有可能在后面跟一些选项,当既有参数又有选项的时候,利用位置参数去获取参数和选项就比较麻烦了,这时我们一般使用getopt明令或者getopts命令。

getopt命令可以接受一系列任意形式的命令行选项和参数,并自动将他们转换成适当的格式。命令格式为:

getopt optstring parameters

optstring定义了命令行有效的选项字母,还定义了那些选项字母需要参数值(在选项后面加冒号)。如果最后输入了一个不在optstring中的选项,默认情况下或报错,如果想忽略报错则需要在getopt后面加一个-q选项。

parameters则是传入的选项和参数。举例如下,输入的结果中用双破折号来分隔选项和参数,由于-d选项是没有提前指定的,所以避免报错,加了一个-q选项。

强调:optstring中只指定选项,以及选项需要的参数(test1),至于其他的参数(test2,test3)不用指定。

注意,在脚本中使用getopt命令时,格式稍有变化:

set -- $(getopt optstring "$@")

这里getopt原始的命令行参数传给getopt,再将getopt输出的数据传个set,这样就到了格式化后的命令行参数,就像上一个例子中的那样,选项与参数之间用双破折号分隔,然后就可以用遍历来获取所有的选项和参数了。

执行结果如下:

getopt也有办不到事情,就是它没法处理带有空格和引号的参数,这时就需要用到getopts命令。

getopts命令除了可以处理带有空格和引号的参数之外,还有其他的高级功能。每次调用getopts,他都只处理一个参数,当处理完所有参数时,会返回一个大于0的退出状态码,这个很适合用来做参数的循环遍历。格式如下:

getopts optstring variable

optstring和上面那个基本类似,只是如果需要去掉错误信息的话,则在optstring前面添加一个冒号。而variable保存的则是在循环中的当前选项。注意只保存选项,而不保存参数,同时他会去掉选项前面的破折号。

结果如下:

getopts还会用到两个环境变量,OPTARG,OPTIND,其中,OPTARG保存的是当前选项中的参数值(如果有参数的话),OPTIND则保存的是下一个要被处理的参数的位置,第一个参数的位置为1。注意,getopts命令在解析选项的时候会移除选项靠头的破折号,上面也有提到过。

执行结果如下:

这里需要注意OPTIND这个参数的值,它保存的是下一个参数的位置,第一个参数的位置为1,即OPTIND的初始值为1,每调用一次getopts,OPTIND就会去获取下一个参数的位置。注意上面的两个输出结果,在第一个结果中由于a,b选项是连着写的,所以他们都在位置1的地方,又由于b选项有一个参数,参数占了一个位置,所以选项c的位置是3,选项c又有一个参数,所以选项d的位置是5,后面的位置6是即将处理的参数的位置,只是该位置还有参数。第二个结果中,由于a,b选项分开写了,所有导致从b开始的参数的位置都比上面那个结果多了1。

这时又会发现,这里只传了选项以及选项携带的参数,而没有单独传入的参数,这时,如果需要处理这些参数应该怎么做呢?如下:

注意这里用到了  shift $[ $OPTIND - 1 ],因为OPTIND指向的是下一个即将处理的参数的位置,而减1操作是得到所有选项占用的位置数,所以用shift $[ $OPTIND - 1 ]来让所有参数向左移动,这样剩下在参数就只是选项后面的那些参数了,这样就可以单独处理了。执行结果如下:

getopts可以将选项字母和参数值连在一起写而不用加空格。可以让未定义的选项统一输出为问号(?)。

执行结果如下:

运行中用获取户输入

read命令会阻塞等待输入并接受输入,将输入的值放进发一个变量中。read后面可以加一个-p选项,这样就可以直接在read命令后面指定提示符。

执行结果为:

read命令还可以将输入的数据分配给多个变量,前提是要指定多个变量,而如果变量数不够,则剩下的数据全都分配给最后一个变量。

执行结果如下:

而如果不指定变量,那么read命令会默认将接收到的数据放到REPLY这个环境变量中。

执行结果如下:

-t选项可以指定read命令等待输入的秒数,如果超时,read命令会返回一个非零推出状态码。

如果我在五秒内输入参数,就会打印我输入的参数,否则会提示我超时。执行结果如下:

还可以限定输入字符的个数(使用选项-n和一个数值),达到字符数后,自动退出(即不需要按回车键),并将输入的数据赋给变量。

执行结果如下,输入一个字符后不用点击任何按钮,就会自动赋值变量然后向后运行:

在输入密码时,还可以将密码隐藏起来,使用-s选项。

执行结果如下,输入时并没有显示出来,但是依然可以正常调用:

read命令还可以读取文件中的数据,每调用一次,读取一行,当读取完毕时,read命令会退出,并返回非零退出状态码。常见的方法是对文件使用cat命令,然后通过管道传输给含有read命令的while命令。

执行结果如下:

发布了49 篇原创文章 · 获赞 10 · 访问量 9264

猜你喜欢

转载自blog.csdn.net/heibuliuqiu_gk/article/details/95390360