九、处理用户输入
读取参数
位置参数变量是标准的数字
$0是脚本名
$1是第一个参数
$2是第二个参数
...
每个参数都是用空格分隔,如果参数值有空格需要使用引号(单双引号都行)
如果要获取第10个参数及其以上需要加上花括号如${10}
[root@tzPC 14Unit]# bash test4.sh 1 2 3 4 5 6 7 8 9 10 11 The tenth parameter is 10 The total is 110 [root@tzPC 14Unit]# cat test4.sh #!/bin/bash echo The tenth parameter is ${10} total=$[ ${10} * ${11} ] echo The total is $total
读取脚本名
使用$0,这里需要注意,$0获取的脚本名有时候是全路径的,我们只要脚本名的话需要使用basename命令。
[root@tzPC 14Unit]# bash /root/script/14Unit/test5.sh The script name is : test5.sh [root@tzPC 14Unit]# cat test5.sh #!/bin/bash #Using basename with the $0 parameter name=$(basename $0) echo echo The script name is : $name
注意,在使用位置参数时需要判断脚本是否有参数传递,没有则会报错
[root@tzPC 14Unit]# cat test7.sh #!/bin/bash #testing parameters before use if [ -n "$1" ] then echo Hello $1 else echo "Sorry" fi
参数统计
$#统计命令行参数个数
可以配合if-then语句中的-ne测试命令行参数数量,参数数量不对给予提示。
取命令行最后一个参数是${!#}而非${$#},因为在花括号内不能使用$
[root@tzPC 14Unit]# cat test8.sh #!/bin/bash #Grabbing the last parameter params=$# echo The last parameter is $params echo The last parameter is ${!#}
当命令行没有参数时,$#值为0,${!#}变量会返回命令行的脚本名
抓取所有数据
$*将命令行所有参数当作一个单词保存,视为一个整体
$@将命令行所有参数当作一个字符串,多个独立单词,可以使用遍历
移动变量
shift命令
默认会将每个参数向左移动一个位置。
变量$3移到$2,$2移到$1,$1的值会被删除,$0值不变还是脚本名
可用于不知道多少个参数的遍历。
[root@tzPC 14Unit]# cat test9.sh #!/bin/bash #demonstrating the shift command count=1 while [ -n "$1" ];do echo "Parameter $count = $1" count=$[ $count +1 ] shift done
可以一次性移动多个位置,shift n
[root@tzPC 14Unit]# bash test10.sh 1 2 3 4 5 The original parameters: 1 2 3 4 5 Here's the new first parameter:3 [root@tzPC 14Unit]# cat test10.sh #!/bin/bash #demonstrating a multi-position shift echo "The original parameters: $*" shift 2 echo "Here's the new first parameter:$1"
处理选项跟参数
使用getopt命令
命令格式
getopt optstring parameters
getopt命令可以接受一系列任意形式的命令行选项和参数,并将它们转成适当的格式。
在getopt命令后的optstring中写出要在脚本中用到的选项跟参数,在每个需要参数的选项后加一个冒号。
[root@tzPC 14Unit]# getopt ab:cd -a -b test1 -cd test2 test3 -a -b test1 -c -d -- test2 test3
在linux中,双破折号表示选项列表结束,后面都是参数
在如上例子中,b后面冒号表示跟参数test1,选项有-a -b -c -d其中-d后面都是参数。
parameters中指定了一个不在optstring中的选项会报错,可以使用-q忽略错误信息
[root@tzPC 14Unit]# getopt ab:cd -a -b test1 -cde test2 test3 getopt:无效选项 -- e -a -b test1 -c -d -- test2 test3 [root@tzPC 14Unit]# getopt -q ab:cd -a -b test1 -cde test2 test3 -a -b 'test1' -c -d -- 'test2' 'test3'
在脚本中使用getopt
使用set命令的--选项能把原本命令行的选项跟参数值传给getopt命令处理,getopt命令处理后会把结果替换原来的命令行选项和参数。(书里写的太绕口了,同时还有一处错误,没有写-d会出现一条错误信息)
写法如下
set -- $(getopt -q ab:cd "$@")
要求:a、b、c、d是脚本的选项,其中b选项有个参数,判断脚本输入的选项跟参数
[root@tzPC 14Unit]# bash test18.sh -ab test -c -d bbb aaa -a option -b option,with parameter value 'test' -c option -d option parameter #1: 'bbb' parameter #2: 'aaa'
脚本如下
[root@tzPC 14Unit]# cat test18.sh #!/bin/bash #Extact command line options & values with getopt set -- $(getopt -q ab:cd "$@") while [ -n "$1" ] do case "$1" in -a)echo "-a option";; -b)param="$2" #esac后面的shift每次循环都将参数左移,所以现在$2时b选项后的参数,后面的shift将把b选项的参数左移。 echo "-b option,with parameter value $param" shift;; -c)echo "-c option";; -d)echo "-d option";; --) shift break ;; #遇到--说明后面都是参数,跳出循环 *)echo "$1 is not an option";; esac shift done #输出参数 count=1 for param in "$@" do echo "parameter #$count: $param" count=$[ $count + 1 ] done
getopt命令会把空格当成参数分隔符,而不是根据双引号把带有空格的参数当作一个整体。
[root@tzPC 14Unit]# bash test18.sh -ab aaa -cd "bbb ccc" ddd -a option -b option,with parameter value 'aaa' -c option -d option parameter #1: 'bbb parameter #2: ccc' parameter #3: 'ddd'
这种情况得使用getopts命令
getopts命令
- 是bash自带命令
- 处理完所有参数后会退出并返回一个大于0的退出码
- 与getopts不同的是,去掉错误消息需要在optstring之前加一个冒号
- 会用到两个环境变量,OPTARG会保存选项跟的参数值,OPTIND保存了参数列表中正在处理的参数位置
- 参数值可以包含空格
- 解析命令行选项时会移除开头的-,所以case下的选项没有-
- 会将命令行中未定义的选项都统一输出为问号
效果如下
[root@tzPC 14Unit]# bash test19.sh -a -b "abc cba" -d -a option -b option,with value abc cba Unknown option: ?
脚本如下
[root@tzPC 14Unit]# cat test19.sh #!/bin/bash #simple demonstration of the getopts command while getopts :ab:c opt do case "$opt" in a) echo "-a option";; b) echo "-b option,with value $OPTARG";; c) echo "-c option";; *) echo "Unknown option: $opt";; esac done
测试$OPTIND变量
代码如下
[root@tzPC 14Unit]# cat test19.sh #!/bin/bash #simple demonstration of the getopts command while getopts :a:b:cd: opt do case "$opt" in a) echo "-a option,with value $OPTARG $OPTIND" ;; b) echo "-b option $OPTIND,with value $OPTARG $OPTIND";; c) echo "-c option" $OPTIND;; d) echo "-d option " $OPTIND,with value $OPTARG $OPTIND;; *) echo "Unknown option: $OPTIND";; esac done shift $[ $OPTIND - 1 ] echo count=1 for param in "$@" do echo "Parameter $count: $param" count=$[ $count + 1 ] done
结果
[root@tzPC 14Unit]# bash test19.sh -b bbb -a aaa -c -d ddd -b option 3,with value bbb 3 -a option,with value aaa 5 -c option 6 -d option 8,with value ddd 8
$OPTIND变量计算方式为test19.sh位置为1,-b为2,bbb参数为3,-a为4,aaa参数为5,-c为6,-d为7,ddd参数为8
获取用户输入
可以一次读取多个变量的值,值与值之间使用空格分割,read命令后面没有指定变量名则会赋值给特定环境变量REPLY
[root@tzPC ~]# read a b
hello world
[root@tzPC ~]# echo $a
hello
[root@tzPC ~]# echo $b
world
[root@tzPC ~]# echo $a $b
hello world
read常见用法及参数
-s 隐藏你输入的信息
[root@tzPC ~]# read -s passwd
-p 提示信息
[root@tzPC ~]# read -p "input your passwd:" -s passwd
也可以使用echo -n,-n的意思是不换行
[root@tzPC ~]# echo -n "please input:" ; read pass
-t 限制输入时间,单位秒
如果定时器过期,read命令会以非零退出状态码退出
[root@tzPC 14Unit]# bash test25.sh Please enter your name: Sorry, too Slow! [root@tzPC 14Unit]# cat test25.sh #!/bin/bash #timing the data entry if read -t 5 -p "Please enter your name: " name then echo "Hello $name,welcome to my script" else echo echo "Sorry, too Slow!" fi
-n 输入长度限制
[root@tzPC 14Unit]# bash test26.sh Do you want to continue [Y|N]? y fine, continue on... [root@tzPC 14Unit]# cat test26.sh #!/bin/bash #getting just one character of input read -n1 -p "Do you want to continue [Y|N]? " anser case $anser in Y | y )echo echo "fine, continue on...";; N | n )echo echo "OK,goodbye" exit;; esac
-r 可以输入空格,\等特殊字符
[root@tzPC ~]# read -r line !@#!@# !@# 123 \n
从文件中读取
调用read命令读取文件,每次会从文件中读取一行文本,读完后返回非零状态码。
[root@tzPC 14Unit]# bash test28.sh Line 1: 123 Line 2: 321 Line 3: 1234567 [root@tzPC 14Unit]# cat test28.sh #!/bin/bash #reading data from a file count=1 cat test | while read line do echo "Line $count: $line" count=$[ $count + 1 ] done
练习
vim test_read.sh
[root@tzPC ~]# cat test_read.sh #!/bin/bash read -p "请输入姓名:" NAME read -p "请输入年龄:" AGE read -p "请输入性别:" SEX cat<<eof ***************************** 你的基本信息如下: 姓名:$NAME 年龄:$AGE 性别:$SEX ****************************** eof
学习来自:《Linux命令行与Shell脚本大全 第3版》第14章