我在 bash 脚本中有以下几行:
while true; do
DATE=date
FORMAT="%Y%m%d"
read -p "Enter start date (YYYYMMDD) " STARTDATE
if date=$(date -d "$STARTDATE" +'+%Y%m%d'); then
start_date=`$DATE +$FORMAT -d $STARTDATE`
echo $start_date
break
fi
echo "Please use right format (YYYYMMDD) "
done
只要输入是 8 个数字(例如,它接受“20210901”并拒绝“20213131”),此方法就可以正常工作。然而,当输入完全关闭时(例如“a”或“废话”),它只需要今天的日期。如何修改代码以更严格地检查格式?
修改后的代码如下:
valid=0
while true; do
DATE=date
FORMAT="%Y%m%d"
read -p "Enter start date (YYYYMMDD) " initialdate
if date=$(date -d "$initialdate" +'+%Y%m%d'); then
start_date=`$DATE +$FORMAT -d $initialdate`
if [[ "$start_date" =~ ^[[0123456789]]{8}$ ]]
then
valid=1
echo "valid";
echo $start_date
break
else
echo "Invalid format"
fi
fi
echo "Please use right format (YYYYMMDD) "
done
答案1
进行输入验证的常见方法是使用无限循环,一旦输入得到验证,您就可以打破该循环。
在这种情况下,“已验证”意味着输入字符串仅包含八位数字,并且 GNUdate
能够使用该日期作为其-d
选项的选项参数。
有了bash
,我们可以把它写成
while true; do
read -r -p 'Input date: '
if [[ $REPLY =~ ^[[:digit:]]{8}$ ]] && date -d "$REPLY" >/dev/null 2>&1
then
break
fi
echo 'Invalid format, try again' >&2
done
thedate=$REPLY
这会读取循环开始时的日期,然后使用正则表达式对其进行测试,如果字符串仅包含八位数字,则该正则表达式将匹配。如果该测试通过,则还会使用 GNU 测试该字符串date
。如果进展顺利,循环将通过break
语句退出。
在 中sh
,我们需要将正则表达式匹配替换为 shell 模式匹配:
while true; do
printf 'Input date: ' >&2
read -r REPLY
case $REPLY in
*[![:digit:]]*)
;;
????????)
date -d "$REPLY" >/dev/null 2>&1 && break
esac
echo 'Invalid format, try again' >&2
done
thedate=$REPLY
这里的测试首先测试字符串是否包含数字以外的任何其他字符。如果该测试失败,则下一次测试恰好是八个字符。如果测试成功,我们将得到一个八位数字的字符串,我们使用 GNU 进行测试date
,如果日期正确则退出循环。
答案2
由于您可以将任务简化为额外的检查,要求输入恰好包含 8 位数字,并且您使用的是 Bash,因此您可以利用正则表达式比较运算符:
if [[ "$startdate" =~ ^[0123456789]{8}$ ]]; then echo "valid"; else echo "invalid"; fi
这将检查 的内容是否$startdate
符合恰好由八位数字组成的正则表达式。
您可以将其组合如下:
valid=0
while (( valid == 0 )); do
valid=1
IFS= read -r -p "Enter start date (YYYYMMDD): " startdate
if [[ ! "$startdate" =~ ^[0123456789]{8}$ ]]; then valid=0;
elif ! date -d "$startdate" +%Y%m%d > /dev/null 2>&1 ; then valid=0; fi
if (( valid == 0 )); then printf "Invalid date entered\n"; fi
done
# < ... operations for valid date here ... >
作为基本规则:
- 推荐使用
shellcheck
,也可作为许多 Linux 发行版上的独立程序来验证您的 shell 脚本。 - 不鼓励使用全大写的变量名称,除非您想将它们导出为环境变量,以避免
$PATH
意外覆盖关键设置。
答案3
或者没有无限循环,并假设 BSD 的date(1)
命令:
REPLY=
valid=false
while ! $valid; do
read -r -p 'Input date: '
if ([[ $REPLY =~ ^[[:digit:]]{8}$ ]]) && (date -j +%Y%m%d ${REPLY}0000 >/dev/null 2>&1)
then
valid=true
else
echo 'Invalid format, try again' >&2
fi
done
thedate=$REPLY
该${REPLY}0000
语法是必要的,因为 BSDdate
需要完整的 YmdHM,但默认 HM 就0000
足够了。