九、处理用户输入

读取参数

位置参数变量是标准的数字

$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命令

  1. 是bash自带命令
  2. 处理完所有参数后会退出并返回一个大于0的退出码
  3. 与getopts不同的是,去掉错误消息需要在optstring之前加一个冒号
  4. 会用到两个环境变量,OPTARG会保存选项跟的参数值,OPTIND保存了参数列表中正在处理的参数位置
  5. 参数值可以包含空格
  6. 解析命令行选项时会移除开头的-,所以case下的选项没有-
  7. 会将命令行中未定义的选项都统一输出为问号

效果如下

[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章

posted @ 2020-07-16 10:27  努力吧阿团  阅读(191)  评论(0编辑  收藏  举报