密码过期脚本:无效日期错误与'never'字符串比较问题修复
问题描述
我尝试编写Bash脚本通知用户密码即将过期,参考相关教程修改后,发现当密码设置为永不过期(即$userexp等于'never')时,字符串比较没有按预期跳过后续代码,导致出现错误:date: invalid date ‘ never’。脚本代码如下:
#!/bin/bash # user=user HOST=`uname -n` # convert current date to seconds currentdate=$(date +%s) # find expiration date of user userexp=$(chage -l $user | grep 'Password expires' | cut -d: -f2) if [[ ! -z $userexp ]] then # convert expiration date to seconds #passexp=$(date -d "$userexp" "+%s") if [ "$userexp" = "never" ] then echo "Password for $user in $HOST is set to never expire" else # convert expiration date to seconds passexp=$(date -d "$userexp" "+%s") # find the remaining days for expiry (( exp = $passexp - $currentdate )) # convert remaining days from sec to days (( expday = $exp / 86400 )) if (($expday < 10 )) then echo "Password for $user in $HOST will expire in $expday day/s" else echo "Password for $user in $HOST still have much time to expire" fi fi fi
问题原因
问题出在userexp变量的内容上!当你用cut -d: -f2提取冒号后的内容时,chage -l的输出里Password expires:后面是带有前导空格的,比如实际输出是:
Password expires: never
所以cut提取到的内容是 never(注意前面有空格),而不是你期望的never。这就导致[ "$userexp" = "never" ]的比较永远不成立,代码会进入else分支,把带空格的 never传给date命令,自然就报错了。
修复方案
这里有几种可靠的修复方式,你可以任选其一:
方式1:去除变量前后的空格(推荐)
在提取userexp时,用xargs来自动去除字符串前后的空格和换行符:
userexp=$(chage -l $user | grep 'Password expires' | cut -d: -f2 | xargs)
xargs会自动修剪掉字符串首尾的空白字符,这样$userexp就会是纯never,比较就能正常生效了。
方式2:用正则表达式匹配
用Bash的[[ ]]结构支持正则匹配,这样不管never前后有多少空格,都能匹配到:
if [[ $userexp =~ never ]]
方式3:匹配带空格的字符串(不推荐,不够健壮)
如果你不想修改变量提取的方式,可以直接匹配带前导空格的字符串:
if [ "$userexp" = " never" ]
但这种方式不够灵活,如果输出里的空格数量变化(比如多个空格),比较就会失效,所以还是前两种方式更可靠。
修改后的完整脚本
这里是用方式1修复后的完整脚本:
#!/bin/bash user=user # 记得这里填上实际要检查的用户名 HOST=$(uname -n) # convert current date to seconds currentdate=$(date +%s) # find expiration date of user, trim whitespace userexp=$(chage -l $user | grep 'Password expires' | cut -d: -f2 | xargs) if [[ ! -z $userexp ]] then if [ "$userexp" = "never" ] then echo "Password for $user in $HOST is set to never expire" else # convert expiration date to seconds passexp=$(date -d "$userexp" "+%s") # find the remaining days for expiry (( exp = passexp - currentdate )) # convert remaining days from sec to days (( expday = exp / 86400 )) if (( expday < 10 )) then echo "Password for $user in $HOST will expire in $expday day/s" else echo "Password for $user in $HOST still has much time to expire" fi fi fi
另外我还修正了一处小细节:把still have改成了still has,语法更准确;同时在算术表达式里去掉了多余的$(Bash算术上下文里变量不需要加$引用)。
内容的提问来源于stack exchange,提问作者xrkr

