hao1nan 发表于 2018-8-30 09:26:31

bash shell笔记4 处理用户输入(交互)

  知识体系:
  #使用命令行参数
  #设置选项
  #获取用户输入
  有时编写的脚本需要能和运行脚本的人员进行交互,bash shell提供了一些方法来从用户处获取数据,这些方法有如下三种:
  1- 命令行参数(添加在命令后的参数)
  2- 命令行选项(修改命令行为的单字符串)
  3- 直接读取键盘输入
  1、命令行参数
  向shell脚本传递数据最基本的方式就是命令行参数,主要就是说通过一些特殊变量是的bash shell自动把输入的参数赋值给变量才执行脚本。这些变量叫做位置参数,分别有$1为第一个参数、$2为第二个参数、$0为程序名称。。。
  1.1、读取参数
  如下看个例子就能理解这个位置参数的概念了:
  # chmod u+x 1.1test
  # cat 1.1test
  #!/bin/bash
  a=1
  for (( b=1; b 1.2test
  # cat 1.2test
  #!/bin/bash
  name=`basename $0`
  if [ $name = "51cto" ]
  then
  echo $name is a great IT community
  elif [ $name = "netease" ]
  then
  echo $name is a great internet-sp corparation
  fi
  # ./51cto
  51cto is a great IT community
  # ./netease
  netease is a great internet-sp corparation
  上面的例子通过脚本名称实现了不同内容的输出,可知basename好用啦!
  脚本是先判断basename,然后根据basename执行函数。
  1.3、测试参数
  在shell脚本中使用命令行参数要小心,如果执行脚本缺少必要的参数,则会出现报错信息,如下:
  # cat 1.1test
  #!/bin/bash
  total=$[ ${10} + ${11} ]
  echo the tenth param is ${10}
  echo the elevnth param is ${11}
  echo the total is $total
  # ./1.1test
  ./1.1test: line 2: +: syntax error: operand expected (error token is " ")
  the tenth param is
  the elevnth param is
  the total is
  我们不输入任何命令行参数,则脚本无法执行。
  所以,我们可以通过-n这个参数进行检测:
  # cat 1.2test
  #!/bin/bash
  if [ -n "$1" ]
  then
  echo $1 exists !
  else
  echo your inputting is wrong
  fi
  # ./1.2test twentyfour
  twentyfour exists !
  # ./1.2test
  your inputting is wrong
  由此可见,通过该方法是检测参数是否存在的好方法。
  2、特殊的参数变量
  在bash shell中有一些特殊的变量用户跟踪命令行参数。
  2.1、参数计数
  我们可以使用bash shell提供的特殊变量$#来检测执行脚本时所包含的命令行参数的个数,看如下例子:
  # cat 2.1test
  #!/bin/bash
  echo there were $# parameters supplied.
  # chmod u+x 2.1test
  # ./2.1test
  there were 0 parameters supplied.
  # ./2.1test aa bb cc
  there were 3 parameters supplied.
  所以,$#是一个值得我们记住脑中的好变量!
  2.2、获取所有参数
  有时候需要获取命令行中的参数,并对它们进行迭代。这里主要通过两个变量来实现对命令行参数的迭代,分别是:
  变量$*和变量$@
  变量$*将所有参数视为一个单词
  变量$@将分别对待每个参数
  我们看个例子\(≧▽≦)/
  # chmod u+x 2.2test
  # cat 2.2test
  #!/bin/bash
  a=1
  for param1 in "$*"
  do
  echo "\$* parameter #$a = $param1"
  a=$[ $a+1 ]
  done
  b=1
  for param2 in "$@"
  do
  echo "\$# parameter #$b = $param2"
  b=$[ $b+1 ]
  done
  c=1
  for param3 in "$#"
  do
  echo "the total counts = $param3"
  c=$[ $c+1 ]
  done
  # ./2.2test a b c d e f
  $* parameter #1 = a b c d e f
  $# parameter #1 = a
  $# parameter #2 = b
  $# parameter #3 = c
  $# parameter #4 = d
  $# parameter #5 = e
  $# parameter #6 = f
  the total counts = 6
  通过一个for循环迭代特殊变量,充分体现出$*$@$#三个特殊变量用途!
  3、移位
  bash shell提供了一个工具叫shift命令,实现改变命令行参数的相对位置
  默认将每个参数变量左移一位。即为,$3的值移动给变量$2($n+1->$n),而变量$1则被丢弃,当然,$0这个程序名称没变。下面看个例子:
  # cat 3test
  #!/bin/bash
  count=1
  while [ -n "$1" ]
  do
  echo "parameter #$count = $1"
  count=$[ $count + 1 ]
  shift
  done
  # chmod u+x 3test
  # ./3test 51cto emc linux rac
  parameter #1 = 51cto
  parameter #2 = emc
  parameter #3 = linux
  parameter #4 = rac
  每测试一个参数,使用shift命令将参数移前一位,所以通过while循环即可是的每个参数都变成$1被循环下去显示出来。当然,我们可以指定shift的位数,而不是默认的一位。看如下例子:
  # cat 3test
  #!/bin/bash
  echo "the original parameter : $*"
  shift 3
  echo "the new shift parameter is : $1"
  # ./3test aa bb cc dd ee
  the original parameter : aa bb cc dd ee
  the new shift parameter is : dd
  指定位数为3后,aa bb cc则被忽略了,直接把dd当成$1.
  4、处理选项
  选项是有破折号引导的单个字母,它更改命令的行为。如下罗列一些标准化选项:
  **********************************************
  选项描述
  -a实现所有对象
  -c生成计数
  -d指定目录
  -e展开对象
  -f指定读取数据的文件
  -h显示命令的帮助信息
  -i忽略大小写
  -l生成长格式的输出
  -n使用非交互式(批量)模式
  -o指定一个输出文件来重定向输出
  -q以quite模式退出
  -r递归处理目录和文件
  -s以silent模式执行
  -v生成verbose模式
  -x排除和拒绝
  -y设置所有提问回答为yes
  **********************************************
  4.1、处理简单选项
  先来看一个例子:
  # cat 4test
  #!/bin/bash
  while [ -n "$1" ]
  do
  case "$1" in
  -a) echo "the -a option exists";;
  -b) echo "the -b option exists";;
  -c) echo "the -c option exists";;
  *) echo "the '$1' is not an option ";;
  esac
  shift
  done
  # ./4test -a -b -c -d -e
  the -a option exists
  the -b option exists
  the -c option exists
  the '-d' is not an option
  the '-e' is not an option
  通过case语句循环判断各个选项,并且通过shift灵活移动选项变量。
  4.2、从参数中分离选项
  执行shell脚本经常会遇到使用选项又需要使用参数的情况。在linux中的标准方式是通过特殊字符码(--,双破折号)将二者分开,表示说当这个脚本程序发现双破折号后,就自动把剩余的命令行视为参数,而不再是选项了,如下看个例子:
  # cat 4test
  #!/bin/bash
  while [ -n "$1" ]
  do
  case "$1" in
  -a) echo "the -a option exists";;
  -b) echo "the -b option exists";;
  -c) echo "the -c option exists";;
  --) shift
  break;;
  *) echo "the '$1' is not an option ";;
  esac
  shift
  done
  count=1
  for param in $@
  do
  echo "parameter #$count:$param"
  count=$[ $count + 1 ]
  done
  # ./4test -a -c -f -- -b test
  the -a option exists
  the -c option exists
  the '-f' is not an option
  parameter #1:-b
  parameter #2:test
  如上先通过while循环,把满足条件的选项显示出来,不满足条件的选项也显示出,并说明 is not an option ,当使用--把剩下的被脚本识别为参数的命令行则通过break跳出循环,并且在shift作用下置位成$1,然后在for循环下逐一显示出来,表示现实出来的即为参数,而非选项!
  如上的脚本得仔细分析,不然很容易出错。
  如果不通过双破折号隔离,如下的结果也是我们想象之中的:
  # ./4test -a -c -f -b test
  the -a option exists
  the -c option exists
  the '-f' is not an option
  the -b option exists
  the 'test' is not an option
  完全是while循环的判断,没法跳出来执行for循环。
  5、获取用户输入
  有时在脚本执行过程中需要询问一个问题并等待执行脚本的人员应答,bash shell提供的read命令可以实现这一需求。
  5.1、基本读取
  read命令接受标准输入(键盘输入),如下示例:
  # chmod u+x 5.1test
  # cat 5.1test
  #!/bin/bash
  echo -n "please input your name:"
  read name
  echo "hello $name, welcome to IT website"
  # ./5.1test
  please input your name:twentyfour
  hello twentyfour, welcome to IT website
  通过一个-n选项使得脚本执行输入不用换行显示。
  如上通过echo显示结果,实际上可以直接通过read命令在-p选项下直接把输入的内容附加给后面指定的变量,如下例子,效果跟上面完全一样:
  # cat 5.1test
  #!/bin/bash
  read -p "please input your name:" name
  echo "hello $name, welcome to IT website"
  # ./5.1test
  please input your name:CCIE
  hello CCIE, welcome to IT website
  所以,我们更多可以采用这种方法。
  如上的两个方法,我们都是把输入的值赋给了变量name,实际上我们可以不使用这个变量name。这么一来,read命令会把输入的命令赋给一个环境变量REPLY,先来看一个效果:
  # read
  the content will be sent to \$REPLY
  # echo $REPLY
  the content will be sent to $REPLY
  我使用\把变量转义不被识别,在read命令下输入的内容将被缓存赋给环境变量$REPLY(这个是系统级别的,直接引用),这下再来看个例子:
  # cat 5.1test
  #!/bin/bash
  read -p "please input your name:"
  echo "hello $REPLY, welcome to IT website"
  # ./5.1test
  please input your name:IBM
  hello IBM, welcome to IT website
  很明显,这个例子跟如上的很接近,但是这个脚本没使用name变量,所以我输入的IBM被系统赋给了环境变量$REPLY。
  5.2、计时
  如上我们可以通过read命令实现交互性的操作,但是假如没有执行脚本的人员操作,脚本则无法自动运行下去。这个时候就可以使用-t选项指定一个计时器,表示等待时间段(单位为秒),如果超过指定的时间,read命令将返回一个非零退出状态,通过判断语句则使脚本可以自动跳过运行下去,我们先看一个例子:
  # chmod u+x 5.2test
  # cat 5.2test
  #!/bin/bash
  if read -t 5 -p "please input your name:"
  then
  echo "hello $REPLY, welcome to come back here"
  else
  echo "sorry , you are too slow "
  fi
  # ./5.2test
  please input your name:twentyfour
  hello twentyfour, welcome to come back here
  # ./5.2test
  please input your name:sorry , you are too slow
  如上通过-t 5是的输入超过5秒则跳到else的判断结果,有点需要注意就是-p必须放置在-t的后面,否则报错!如上我没有任何输入,超过5秒,则脚本返回了sorry , you are too slow的内容。
  到这里还有一个挺经典的-n选项不得不提,除了如上输入时间计时,read还可以通过添加-n选项计数输入的字符。等输入的字符达到预定数目时就自动退出,这里借助case看一个例子:
  # cat 5.2test
  #!/bin/bash
  read -n1 -p "do you want to continue ?"
  case $REPLY in
  Y | y) echo
  echo "fine ,continue on ..";;
  N | n) echo
  echo "OK, goodbye...";;
  esac
  # ./5.2test
  do you want to continue ?y
  fine ,continue on ..
  # ./5.2test
  do you want to continue ?N
  OK, goodbye...
  如上-n后面是数字1,表示read命令接收到一个字符就退出,所以输入Y/N后不用回车就马上执行下去了。这里出现了两个echo,主要是使得结果换行显示,更显人性化。还有就是通过|符号识别大小写,也是人性化。
  5.3、默读
  有时候需要脚本用户进行输入,但输入的数据不显示出来,比如像password的输入。这里可以借用read命令下的-s选项,使得输入的数据颜色跟背景颜色一致,实现不显示数据的效果,看如下例子:
  # cat 5.3test
  #!/bin/bash
  read -s -p "please input your passwd:"
  echo your passwd is $REPLY
  # chmod u+x 5.3test
  # ./5.3test
  please input your passwd:your passwd is aaa
  # ./5.3test
  please input your passwd:your passwd is 51cto
  哈哈,这不失为一个非常棒的选项。还有,别以为数据颜色跟背景颜色一样后,你可以通过数据把数据选上而显示出来,linux命令行下输入的数据不占位,压根无法让你选上!
  5.4、读取文件
  read命令可以读取linux系统上存储的文件数据,每调用一次read命令,都会去读取一行文本(注意,是一行,不是整个文件内容),当read命令读完的文本内容将以非零状态退出。借用while命令看一个例子:
  # cat 5.4test
  #!/bin/bash
  count=1
  cat 51cto.test | while read line
  do
  echo "LINE $count : $line"
  count=$[ $count + 1 ]
  done
  # cat 51cto.test
  aaaaaaaaaa
  bbbbbbbbbb
  cccccccccc
  # ./5.4test
  LINE 1 : aaaaaaaaaa
  LINE 2 : bbbbbbbbbb
  LINE 3 : cccccccccc
  这里的51cto.test跟脚本文件放置同一个目录,当然最后就把要读取的文件以绝对路径写入脚本防止脚本读取不到。while命令使用read不断循环读取文件51cto.test中每一行,然后显示出来,直到read读取完后以非零状态退出而结束!

页: [1]
查看完整版本: bash shell笔记4 处理用户输入(交互)