侧边栏壁纸
博主头像
枕头下放双臭袜子博主等级

今我何功德,曾不事农桑

  • 累计撰写 163 篇文章
  • 累计创建 30 个标签
  • 累计收到 0 条评论

shell脚本学习五(处理用户输入)

枕头下放双臭袜子
2019-11-05 / 0 评论 / 0 点赞 / 677 阅读 / 0 字 / 正在检测是否收录...

处理用户输入:

 1、命令行参数

       向 shell 脚本传递数据的最基本的方法是使用命令行参数,命令行参数允许在运行脚本时向命令行添加数据。

2、读取参数

       bash shell 中有一些特殊变量叫做 位置参数,位置变量参数是标准的数字:$0 是程序名,$1 是第一个参数,$2 是第二个参数,以此类推,直到第九个参数 $9 ,$0~$9 可以定义在脚本中,通过命令行向其赋值。

          

          

          当向 shell 脚本传递字符串时,如果希望将多个字符串当做一个变量,需要加上单引号 ' '

          .

          

          如果脚本需要的命令行参数不止 9 个,你仍然可以处理,但是需要稍微修改一下变量名,在第 9 个变量之后,你必须在变量数字周围加上花括号,比如  ${10}

          

          

3、读取脚本名

         可以使用 $0 参数获取 shell 在命令行启动的脚本名,这在编写多功能工具时很方便

           (同样的脚本如果需要根据不同的脚本名执行不同的功能时,就需要用到 $0 了)

             

             

            但是出现一个潜在的问题,如果使用另一个命令来执行脚本,命令会和脚本名混合在一起出现出现在 $0 参数中

           

               这不是唯一的问题,当传给 $0 变量的实际字符串不仅仅是脚本名,而是完整的脚本路径时,变量 $0 就会使用整个路径

           

        解决这一问题可以使用 basename 命令,它会返回不包含路径的脚本名

          

         

        现在可以结和 $0 和 basename 来编写基于脚本名执行不同功能的脚本了。

           

           

4、 特殊参数变量:

           $# 含有脚本运行时携带的命令行参数的个数,可以在脚本中任何地方使用这个特殊变量,就跟普通变量一样

                           

                         

     基于 $# 实现特定功能:

            

           

      5、 抓取命令行上提供的所有参数: $*     $@

              区别就是: $*    会将所有参数当成单个参数

                                 $@     会单独处理每个参数

              

              

 6、移动变量:

         下面这个脚本通过 shift 命令实现了使用一个参数完成多个数据的遍历,当第一个参数的长度为 0 时,循环结束。测试完第一个参数后,shift 命令会将所有的参数的位置移动一个位置。

 ( 要注意的是:使用 shift 命令时,一定要小心,如果某个参数被移出,它的值就被丢弃了,无法再恢复 )

               

                   留个小疑问:为什么 -n  判断 $1 是否为 0 时要加上双引号?

              

          shift 也可以一次性移动多个位置,例如: shift  2  一次移动 2 

               注意:我们来看下面这个例子,我特意检测了一下当只有 一个特殊变量 $1 却有多个参数时 shift 在 while 和 case 中的具体如何工作的

                   

            此时我们在脚本中先不使用 shift,看看有多个选项时情况如何:

          ( 我们发现它会进行一个死循环,一直输出 - a 选项,不能够读取之后的选项 )

               

             此时我们加上 shift,重新运行你会发现一切正常

                 

                 

             这说明 在 while 和 case 中 ,每执行完一个选项,就需要 shift 一次,将原来的选项移出以此来读取新的选项,这对我们理解接下来的 带参数的选项很有帮助   

7、 处理选项:

                  

            用一组普通的选项和参数来运行这个脚本,结果说明在处理时脚本认为所有的命令行参数都是选项

                       

          当脚本遇到双破折线时,它会停止处理选项,并将剩下的参数都当做命令行参数。

                   

8、处理带值的选项

          有的选项会带上一个额外的参数值,当命令行选项要求额外的参数时,脚本必须能检测到并正确处理。

         ( 这种情况下,如 $ ./testing.sh  -a test1  -b  -c -d   test2 ) 

              

(  此处执行此脚本带有命令行参数为:  ./difOption.sh  -a  -b  test  -c   

                如上文所说,先将 -a 存入 $1 变量,执行完 - a 选项之后执行 do 的 shift 命令将 - a 选项移出,遇到 - b 选项将其存入 $1,因为 - b 选项带有参数 test,所以需要另外准备一个变量 $2 来存入参数值 test,执行完 - b 选项之后,在 - b 选项之后执行一次 shift 将 $1 中的 - b 值移出,再在 while 循环最后执行一次 shift 将被移入 $1 的参数 test 也移出(所以此处是执行了两次 shift ),最后在将 - c 选项读入 $1 变量,自后执行完毕退出)

                     

 9、使用 getopt 命令

                9.1 命令的格式

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

                getopt   optstring   parameters

             optstring 定义了命令行有效的选项字母,还定义了哪些选项字母需要参数值,在 optstring 中列出你要在脚本中用到的每个命令行选项字母,然后,在每个需要参数值的选项字母之后加一个冒号。getopt 命令会基于你定义的 optstring 解析提供的参数

例如:  $ getopt  ab:cd  -a  -b  test1 -cd  test2   test3

                           (-a  -b  test1   -c  -d   --  test2 test3) 

      optstring 定义了四个有效选项字母:a、b、c、d,冒号(:)被放在了字母 b 后面,因为 b 选项需要一个参数值,当 getopt 命令运行时,它会检查提供的参数列表

( -a  -b test1  -cd  test2  test3 ),并基于提供的 optstring 进行解析。注意,它会自动将 - cd 选项分成两个单独的选项,并插入双破折线来分割行中的额外参数

如果指定了一个不在 optstring 中的选项,默认情况下,getopt 会产生一条错误消息。

例如: $ getopt   ab:cd   -a  -b  test1   -cde   test2 test3 

        9.2 在脚本中使用 getopt

              set  -- $(getopt -q  ab:cd  "$@")

             双破折线是 set 命令的的选项之一,它会将命令行参数替换成 set 命令的命令行值,然后该方法会将原始脚本的命令行参数传给 getopt 命令,之后再将 getopt 命令的输出传给 set 命令,用 getopt 格式化后的命令行参数来替换原始的命令行参数。

               

                

               getopt 命令并不擅长处理带空格和引号的参数值,它会将空格当做参数分隔符,而不是根据双引号将两者当做一个参数,我们可以使用 getopts 来解决这个问题。

 10、使用 getopts 命令

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

                 getopts   optstring   variable   

                 有效的选项字母都会列在 optstring 中,如果选项字母要求有个参数值,就加一个冒号。要去掉错误消息的话,可以在 optstring 之前加一个冒号。getopts 命令将当前参数保存在命令行中定义的 variable 中。

                 getopts 命令会用到两个环境变量,如果选项需要跟一个参数值,OPTARG 环境变量就会保存这个值,OPTIND 环境变量保存了参数列表中 getopts 正在处理的参数位置,这样你就能在处理完选项之后继续处理其他命令行参数了。

             

        while 语句定义了 getopts 命令,指明了要查找哪些命令行选项,以及每次迭代中存储它们的变量名(opt),getopts 命令解析命令行选项时会移除开头的单破折线( 即运行脚本时的命令行参数的 - a 等。。),所以在 case 定义中不用单破折线

                  

               getopts 对新手来说有几个好用的功能

              ①可以在参数值中包括空格

                  

               ②可以将选项字母和参数值放在一起使用,而不用加空格

                      

              ③除此之外 getopts 还能够将命令行上找到的所有未定义的选项统一输出成问号

                    

                     

           getopts 命令知道何时停止处理选项,并将参数留给你处理。在 getopts 处理每个选项时,它会将 OPTIND 环境变量值增一,在 getopts 完成处理时,你可以使用 shift 命令和 OPTIND 值来移动参数。

                    

                    

         现在你就拥有了一个能在所有 shell 脚本中使用的全功能命令行选项和参数处理工具

常用的 linux 命令选项 :

选项

描述

-a

显示所有对象

-c

生成一个计数

-d

指定一个目录

-e

扩展一个对象

-f

指定读入数据的文件

--help

显示命令的帮助信息

-i

忽略文本大小写

-l

产生输出的长格式文本

-n

使用非交互模式(批处理)

-o

将所有输出重定向到的指定的输出文件

-q

以安静模式运行

-r

递归的处理目录和文件

-s 

以安静模式运行

-v

生成详细输出

-x

排除某个对象

-y

对所有问题回答 yes

 11、获得用户输入

            11.1  基本的读取

                  read 命令从标准输入(键盘)或另一个文件描述符中接受输入。在收到输入后,read 命令会将数据放进一个变量。

                  

                  

             此处的 echo 使用了 -n 选项,该选项不会在字符串末尾输出换行符,允许脚本用户紧跟其后输入数据,而不是下一行,这让脚本看起来更像表单

             实际上,read  的选项 -p 也允许直接在 read 命令行指定提示符

              

                  

             read 命令会将提示符后输入的所有数据分配给单个变量,要么你就指定多个变量,输入的每个数据值都会分配给变量列表的下一个变量,如果变量数量不够,剩下的数据就全部分配给最后一个变量

             在 read 命令行中也可以不指定变量,如果是这样,read 命令会将它收到的任何数据都放进特殊环境变量 REPLY 中,REPLY 环境变量会保存输入的所有数据,可以在 shell 脚本中像其他变量一样使用

           11.2  超时

              使用 read 命令时脚本很可能会一直苦等着脚本用户的输入,如果不管是否有数据输入,脚本都必须继续执行,你可以使用  - t  选项来指定一个计时器,-t 选项指定了 read 命令等待输入的秒数,当计时器过期后,read 命令会返回一个非零退出状态码

                  

                   

              如果计时器过期,read 命令会以非零退出状态码退出,可以使用 if - then 或 while 循环这种标准的结构化语句来理清所发生的具体情况,在本例中,计数器过期时,if 语句不成立,shell 会执行 else 部分的命令

                也可以让 read 命令来统计输入的字符数,当输入的字符达到预设的字符数时,就自动退出,将输入的数据赋给变量

                   

                   

              本例中将 - n 选项和值 1 一起使用,告诉 read 命令在接受单个字符后退出,只要按下单个字符回答后,read 命令就会接受输入并将它传给变量,无需按回车键

              11.3  隐藏方式读取

               有时候你需要从脚本用户处获得输入,但是又不能在屏幕上显示输入信息,典型的例子就是输入密码,除此之外还有很多其他需要隐藏的数据类型。

               read 命令的 - s 选项可以避免在 read 命令中输入的数据出现在显示器上(实际上,数据会被显示,只是 read 命令会将文本颜色设成跟背景色一样)

                  

                  

             11.4   从文件读取

                   也可以用 read 命令来读取 linux 系统上文件里保存的数据,每次调用 read 命令,它都会从文件中读取一行文本,当文件在没有内容时,read 命令会退出并返回非零退出状态码。

                   最常见的搭配是对文件使用 cat 命令 ,将结果通过管道直接传给含有 read 命令的 while 命令

                      

                    

                 while 循环会持续通过 read 命令处理文件中的行,直到 read 命令以非零退出状态码退出。

0

评论