在日常的系统管理和自动化任务中,使用 Shell 脚本可以为我们节省大量时间和精力。
文章将以输入 IP
为例,通过几个版本逐步完善一个案例。
原始需求
编写一个交互式的 Shell 脚本,运行时让用户可以输入IP地址,并且脚本会将输入的IP地址打印出来。
实现
首先,在命令行终端下创建一个新的文件,比如 i-demo.sh
,并确保该文件具有可执行权限。
touch i-demo.sh
chmod +x i-demo.sh
版本一
shell 编程中,read 命令可以在运行时阻塞线程,并等待用户输入。因此脚本可以简单实现如下:
#!/bin/bashread userIPecho "You entered IP : " $userIP
以上代码中 read
命令用于提示用户输入IP地址,并将用户输入存储在变量 userIP
中。随后,echo
命令用于打印出用户输入的IP地址。
版本二
添加提示符 “Please Input IP:”,使得交互比较友好
#!/bin/bashread -p "Please Input IP: " userIPecho "You entered IP: $userIP"
read -p
是 Shell 脚本中用来提示用户输入的命令。它的作用是在用户输入之前,向屏幕上显示一行提示信息,让用户知道他们需要输入什么样的内容。-p
选项表示 prompt(提示),后面紧跟着要显示给用户的提示信息。
版本三
给一个默认值。
#!/bin/bashdefaultIP=127.0.0.1read -p "Please Input IP: " userIPif [ -z $userIP ]; thenuserIP=$defaultIP
fiecho "You entered IP: $userIP"
其中,if [ -z $userIP ]
表示输入为空时,将 userIP
赋值为默认值 defaultIP
。
另一种实现:
#!/bin/bashdefaultIP=127.0.0.1read -p "Please Input IP: " userIPuserIP=${userIP:-$defaultIP}echo "You entered IP: $userIP"
其中 userIP=${userIP:-$defaultIP}
这行代码将会把 $userIP
的值设置为 $defaultIP
的值,当且仅当 $userIP
未被设置或者为空。这个语法可以用来提供一个默认值,以防止变量为空时的错误。
效果如下:
其中,第一次输出默认值。第二次输出输入的值。
版本四
在光标处展示默认值,并且支持用户直接编辑
#!/bin/bashdefaultIP=127.0.0.1read -p "Please Input IP (default: $defaultIP): " -e -i "$defaultIP" userIPuserIP=${userIP:-$defaultIP}echo "You entered IP: $userIP"
其中 read
命令后的 -e -i "$defaultIP"
将默认IP放置在了光标处,并支持编辑。
效果如下:
上图中第一次直接回车,打印了默认值。第二次直接便捷给出的默认IP,回车后打印编辑后的IP.
版本五
在默认值的基础上添加IP校验,并且校验不通过时,提示再次输入
#!/bin/bashdefaultIP=127.0.0.1# IP 校验函数
function validateIP() {local ip=$1if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; thenlocal IFS=.ip=($ip)(( ${ip[0]} <= 255 && ${ip[1]} <= 255 && ${ip[2]} <= 255 && ${ip[3]} <= 255 ))return $?elsereturn 1fi
}# 提示输入
read -p "Please Input IP (default is $defaultIP): " -e -i $defaultIP userIP
userIP=${userIP:-$defaultIP}# 校验,若不通过一直循环
while true; doif ! validateIP "$userIP"; thenread -p "Invalid IP format ($userIP). Please try again: " userIPelsebreakfi
done# 打印结果
echo "You entered a valid IP: $userIP"
其中
-
local IFS=.
:这行代码中的 IFS 是 Bash shell 中的一个特殊变量,它代表了“Internal Field Separator”(内部字段分隔符),用来指定在 Bash shell 中如何切割字符串。在这行代码中,将 IFS 设置为.
,意味着告诉 Bash 在处理字符串时,以.
作为分隔符来切割字符串。 -
ip=($ip)
: 这行代码使用了 Bash 中的数组赋值语法。它将名为ip
的字符串分割成一个数组,按照内部字段分隔符(IFS)中指定的字符(在这个例子中是.
)进行分割。这意味着,如果$ip
包含了一个IP地址,那么这个命令会把IP地址中的每一部分分别存储到数组ip
的不同元素中。
例如,如果$ip
的值为192.168.1.1
,那么执行ip=($ip)
后,数组ip
的各个元素就会分别存储为${ip[0]} = 192
,${ip[1]} = 168
,${ip[2]} = 1
,${ip[3]} = 1
。 -
(( ${ip[0]} <= 255 && ${ip[1]} <= 255 && ${ip[2]} <= 255 && ${ip[3]} <= 255 ))
:这行代码使用了 Bash 中的算术表达式((...))
,并结合了数组中的值进行了数值比较。
在这里,${ip[0]}
、${ip[1]}
、${ip[2]}
和${ip[3]}
分别代表了 IP 地址中的四个部分。通过将它们与常量值 255 进行比较,并使用逻辑与运算符 && 来连接所有比较操作,可以确保每个部分都不大于 255。
因此,整个表达式的含义是:检查 IP 地址的各个部分是否都小于等于 255。如果所有条件都成立,那么整个表达式的结果为真(非零),否则为假(零)。 -
$?
: 是在Bash中用来获取上一个命令的退出状态的特殊变量。当执行一个命令后,$?
会保存该命令的退出状态或者返回值。
通常情况下,如果命令执行成功,则$?
的值为0;如果命令执行失败,则$?
的值为非零(通常是1)。
在先前提到的代码中,(( ${ip[0]} <= 255 && ${ip[1]} <= 255 && ${ip[2]} <= 255 && ${ip[3]} <= 255 ))
这个条件表达式执行完毕后,它的返回值将会被保存在$?
中。因此,可以使用$?
来检查IP地址校验的结果,如果$?
的值为0,则表示IP地址合法,否则表示IP地址不合法。
其效果如下