读取键盘输入
read —— 从标准输入读取输入值。
内嵌命令read读取一行标准输入,该命令可用于读取键盘输入值或应用重定向读取文件中的一行。
read命令的语法结构是:
read [-options] [variable...]
其中options是一条或者多条选项;variable则是一个到多个的用于存放输入量的变量。若没有提供任何的命令,shell默认变量REPLY来存储数据行。
#!/bin/bash
echo -n "Please enter an integer -> "
read int
if [[ "$int" =~ ^-?[0-9]+$ ]];then
if [ $int -eq 0 ];then
echo "$int is zero"
else
if [ $int -lt 0 ];then
echo "$int is negative."
else
echo "$int is positive."
fi
if [ $((int % 2)) -eq 0 ];then
echo "$int is even."
else
echo "$int is odd."
fi
fi
else
echo "Input value is not an integer." >&2
exit 1
fi
在以下脚本中,read命令将输入值赋给多个变量
#!/bin/bash
# read-multiple:read multiple values from keyboard
echo -n "Enter one or more values > "
read var1 var2 var3 var4 var5
echo "var1 = '$var1'"
echo "var2 = '$var2'"
echo "var3 = '$var3'"
echo "var4 = '$var4'"
echo "var5 = '$var5'"
需要特别注意的是:
当输入少于或者多于5个值得时候,read的运作方式
若read命令读取的值少于预期的数目,则多余的变量值为空;若read命令读取的值多于预期的数目,则最后的变量包含了所有的多余值。
如果read命令之后没有变量,则会为所有的输入值分配一个shell变量:REPLY
有趣的选项
-p 选项来显示提示信息 (取代上面脚本中的echo -n打印语句,作用与之等效)
#!/bin/bash
# read-single:read multiple values into default variable
read -p "Enter one or more values > "
echo "REPLY = '$REPLY'"
使用-s -t选项,可以以“秘密”的形式读取输入的参数,常常用于读取密码输入
#!/bin/bash
# read-secret: input a secret passphrase
if read -t 10 -sp "Enter secret passphrase > " secret_pass;then
echo -e "\nSecret passphrase = '$secret_pass'"
else
echo -e "\nInput timed out" >&2
exit 1
fi
提示用户输入密码,系统的等待时间是10秒。若10秒内用户没有完成输入,脚本以出错状态结束运行。又因为用了-s选项,所以输入的密码不会显示到屏幕上。
使用IFS间隔输入字段
由shell变量IFS(Internal Field Separator)设定,默认值包含空格、换行符和制表符。
我们可以通过改变IFS值来控制read命令输入的间隔方式。
#!/bin/bash
# read-ifs:read fields from a file
FILE=/etc/passwd
read -p "Enter a username > " user_name
file_info=$(grep "^$user_name:" $FILE)
if [ -n "$file_info" ];then
IFS=: read user pw uid gid name home shell <<< "$file_info"
echo "User = '$user'"
echo "Pw = '$pw'"
echo "UID = '$uid'"
echo "GID = '$gid'"
echo "Full name = '$name'"
echo "Home Dir = '$home'"
echo "Shell = '$shell'"
else
echo "No such user '$user_name'" >&2
exit 1
fi
以上脚本知识点:
1、shell命令允许命令执行前对一到多个变量进行赋值,这种赋值方式会改变接下来所执行命令的操作环境。但是赋值的效果是暂时性的,只有在命令执行周期内有效。等效于
OLD_IFS=$IFS
IFS=:
read user pw uid gid name home shell <<< "$file_info"
IFS=$OLD_IFS
显然,对于相同的效果,将变量赋值语句置于执行命令前是更为简洁的方法。
2、操作符 “<<<”象征一条嵌入字符串。与嵌入文档类似,只不过更为简短,它包含的是一条字符串。
为什么不用
echo "$file_info" | IFS=":" read user pw uid gid name home shell
read不可重定向
验证输入
程序具备了读取键盘输入功能的同时,也带来了新的挑战——验证输入。
#!/bin/bash
# read-validate: validate input
invalid_input () {
echo "Invalid input '$REPLY'" >&2
exit 1
}
read -p "Enter a single item > "
# input is empty
[[ -z "$REPLY" ]] && invalid_input
# input is multiple items(invalid)
(( $(echo "$REPLY" | wc -w) > 1 )) && invalid_input
# is inpuot a valid filename?
if [[ "$REPLY" =~ ^[-[:alnum:]\._]+$ ]];then
echo "'$REPLY' is a valid filename."
if [[ -e $REPLY ]];then
echo "And file '$REPLY' exists."
else
echo "However,file '$REPLY' does not exist."
fi
# is input a floating point number?
if [[ $REPLY =~ ^-?[[:digit:]]*\.[[:digit:]+$] ]];then
echo "'$REPLY' is a floating point number."
else
echo "'$REPLY' is not a floating point number."
fi
# is input an integer?
if [[ $REPLY =~ ^-?[[:digit:]]+$ ]];then
echo "'$REPLY' is an integer."
else
echo "'$REPLY' is not an integer."
fi
else
echo "The string '$REPLY' is not a valid filename."
fi
菜单驱动程序
菜单驱动是一种常见的交互方式。在菜单驱动的程序会呈现给用户一系列的选项,并请求用户进行选择。
#!/bin/bash
# read-menu:a menu driven system information program
clear
echo "
Please Select:
1.Display System Information
2.Display Disk Space
3.Display Home Space Utilization
0.Quit
"
read -p "Enter selection [0-3] > "
if [[ $REPLY =~ ^[0-3]$ ]];then
if [[ $REPLY == 0 ]];then
echo "Program terminated."
exit
fi
if [[ $REPLY == 1 ]];then
echo "Hostname: $HOSTNAME"
uptime
exit
fi
if [[ $REPLY == 2 ]];then
df -h
exit
fi
if [[ $REPLY == 3 ]];then
if [[ $(id -u) == 0 ]];then
echo "Home Space Utilization(All Users)"
du -sh /home/*
else
echo "Home Space Utilization($USER)"
du -sh $HOME
fi
exit
fi
else
echo "Invalid entry." >&2
exit 1
fi
以上脚本主要有两部分。第一部分展示了菜单并获取用户的响应,第二部分对响应进行验证并执行相应的选项。
可以关注作者微信公众号,追踪更多有价值的内容!