获得用户输入
基本的读取
read命令比较常用的语法格式:
read [-p prompt] [var1 var2...]
-p选项用于在尝试读取任何输入之前,显示提示信息(prompt)的内容到标准输出。一般情况用来提示用户输入哪些输入信息。
read命令会每次从标准输入读取一行的内容(-u可以指定文件描述符),将第一个单词赋值给第一个变量var1,第二个赋值给var2.......。如果输入的单次数少于指定的变量数,那么剩下的会被设置为空。IFS全局环境变量可以设置输入内容之间的分割符,默认为空格。
如:
[root@rs1 read]# cat read_1.sh #提示用户输入用户名,然后将用户的输入赋值给变量username read -p "Enter your name,please: " username #提示用户输入电话号码,然后赋值给变量email read -p "Enter your tel number,please: " tel #询问用户是否继续,提示输入y或n,然后将用户输入的内容赋值给input read -p "Are your sure to contuinue?[y/n]" input case $input in #如果输入为y或者Y,则显示用户名和电话到标准输出 y|Y) echo "Your name is : $username" echo "Your tel number is : $tel " ;; [nN]*) echo "Bye" exit ;; *) echo "Just input y or n,please" exit 1 ;; esac
执行脚本:
[root@rs1 read]# bash read_1.sh Enter your name,please: fsx Enter your tel number,please: 123 Are your sure to contuinue?[y/n]y Your name is : fsx Your tel number is : 123 [root@rs1 read]# bash read_1.sh Enter your name,please: fsx Enter your tel number,please: 123 Are your sure to contuinue?[y/n]n Bye [root@rs1 read]# bash read_1.sh Enter your name,please: fsx Enter your tel number,please: 123 Are your sure to contuinue?[y/n]Nsd Bye [root@rs1 read]# bash read_1.sh Enter your name,please: fsx Enter your tel number,please: 123 Are your sure to contuinue?[y/n]ttt //参数输入错误的情况 Just input y or n,please
输入超时
可以使用read的-t选项来设置read命令读取用户输入得超时时间。如果在指定的时间内没有读入一行输入(即没有回车),read命令就会返回一个失败。
如:(还是上面的脚本代码,仅仅添加了-t选项)
[root@rs1 read]# cat read_2.sh #提示用户输入用户名,然后将用户的输入赋值给变量username read -t 7 -p "Enter your name,please: " username #提示用户输入电话号码,然后赋值给变量email read -t 5 -p "Enter your tel number,please: " tel #询问用户是否继续,提示输入y或n,然后将用户输入的内容赋值给input read -t 5 -p "Are your sure to contuinue?[y/n]" input case $input in #如果输入为y或者Y,则显示用户名和电话到标准输出 y|Y) echo "Your name is : $username" echo "Your tel number is : $tel " ;; [nN]*) echo "Bye" exit ;; *) echo "Just input y or n,please" exit 1 ;; esac
执行脚本:
[root@rs1 read]# bash read_2.sh //正确输入 Enter your name,please: fsx Enter your tel number,please: 123 Are your sure to contuinue?[y/n]y Your name is : fsx Your tel number is : 123 [root@rs1 read]# bash read_2.sh //输入超时 Enter your name,please: Enter your tel number,please: Are your sure to contuinue?[y/n]Just input y or n,please
拒绝回显输入
read命令可以使用-s选项隐藏用户的输入。如果指定了-s,则来自终端的输入不会回显,这对于用户密码等隐私相关的验证有一定的安全意义。
如:
[root@rs1 read]# cat read_3.sh #定义变量password password='' #显示提示输入密码的信息到标准输出 echo "Enter your password: " #使用while循环隐式地从标准输入每次读取一个字符,且反斜杠不做转义 #将读取的字符赋值给变量char while IFS= read -r -s -n1 char do #如果读入的字符为空(直接输出的空格),则退出while循环 if test -z $char then echo break fi #如果输入的是backspace,则从变量password中移除最后一个字符 #并向左删除一个* #否则,将变量char的值累加赋值给password变量 if [[ $char == $'\x08' ]] then #从变量password中移除最后一个字符 [[ -n $password ]] && password=${password:0:${#password}-1} #并向左删除一个* printf '\b \b' else #将变量char的值累加赋值给变量password password+=$char #打印一个星号 printf "*" fi done echo "Password is : $password"
执行脚本:
[root@rs1 read]# bash read_3.sh Enter your password: *** Password is : fsx
从文件中读取
read命令从文件读取数据的方法主要有两种。一种是在while循环或until循环中使用read命令,通过文件描述符一行一行地读取文件内容。另一种是在for循环中使用cat <filename>来读取文件的内容。
在for循环中使用cat <filename>读取文件的语法:
for data in $(cat <filemae>) do command1 command2 ... done
filename代表一个文本文件,读取的内容回被存入便来嗯data,此变量会在for循环中使用,来对读入的数据进行处理。
如果要按逐行读取文件内容时,要设置IFS的值为\n
如:
[root@rs1 read]# cat read_4.sh ; #!/bin/bash #使用变量O_IFS来保存环境变量IFS的值 old_IFS=$IFS #如果指定的命令行参数个数不为1,则显示脚本使用方法,并退出运行 if test $# -ne 1 then #显示脚本的使用方法信息 echo "Usage: `basename $0` filename" #退出脚本 exit 2 fi #如果指定文件不存在,则显示提示信息,并退出脚本的执行,退出状态码为1 if test ! -f $filename then #提示文件不存在 echo "The file $filename does not exist!" #退出 exit 1 fi #修改环境变量IFS值,使得for循环里面按行读取文件内容 IFS=$'\n' for line in $(cat $1) do echo "$line" echo "tag#######################################" done #恢复IFS的值 IFS=old_IFS
执行脚本:
如果没有执行参数
[root@rs1 read]# bash read_4.sh Usage: read_4.sh filename
如果文件不存在
[root@rs1 read]# bash read_4.sh 1 The file does not exist!
如果文件存在
[root@rs1 read]# bash read_4.sh 1 # tag####################################### # /etc/fstab tag####################################### # Created by anaconda on Tue May 22 08:52:29 2018 tag####################################### # tag####################################### # Accessible filesystems, by reference, are maintained under '/dev/disk' tag####################################### # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info tag####################################### # tag####################################### /dev/mapper/rhel-root / xfs defaults 1 1 tag####################################### UUID=35ae0b8d-9734-4f72-8a4c-1ae16123f407 /boot xfs defaults 1 2 tag####################################### /dev/mapper/rhel-swap swap swap defaults 0 0 tag#######################################
while的副作用:当读取每行内容会去掉重复的空格和制表符,即会消除每行的原本格式。
for循环结合IFS保留了原本的格式。
总结
可以使用函数传递命令行参数的方法,向Shell脚本传递参数。传递的命令行参数存储在位置参数{$1,$2,$3...${10}...}
特殊变量"$*"和"$@"会存储所有传递的命令行参数,"$#"会存储传递的命令行参数的个数
当只接受一个参数时,使用case命令比较合适。case常见于Linux下的应用程序或服务的启动脚本中
case语句中的每个模式匹配时大小写敏感的,可以使用"shopt -s nocasematch"开启nocasematch选项
当使用多个命令行参数时,可以使用shift命令在一个变量中一个接一个的获取命令行参数
shift时Bash的一个内部命令。此命令用于将传递的参数变量左移,每次移动,$1和$#都会因之改变
为了使得Shell脚本严谨,在脚本开头一般会编写一段与脚本环境或变量进行检查的代码
getopts和getopt时更为专业的解析命令行选项和参数的工具
read命令的-p选项用于显示提示信息到标准错误里面
read命令的-t选项可以用来设置用户的输入超时时长
read命令的-s选项,可以设置输入不回显
使用read读取文件中数据的方式有两种:while/until循环;for循环。使用for循环时注意IFS的值