![Bash:IF-THEN 语句中的“参数太多”](https://linux22.com/image/212210/Bash%EF%BC%9AIF-THEN%20%E8%AF%AD%E5%8F%A5%E4%B8%AD%E7%9A%84%E2%80%9C%E5%8F%82%E6%95%B0%E5%A4%AA%E5%A4%9A%E2%80%9D.png)
我正在尝试检查特定文件是否存在(但仅当存在时间少于 24 小时时),如果存在,则执行第二次检查以查看名称以“.control”结尾的文件是否存在。如果满足这两个条件,则创建电子邮件和日志条目。如果第一个文件存在但 .control 不存在,则创建不同的日志条目。如果不到 24 小时的文件不存在,则继续执行脚本的其余部分。
这是在 Solaris 和 Linux 上使用 Bash 从 cron 启动的 shell 脚本中。
if [ find "$MAINTENANCE_LOCK/testLOCK" -mtime -1 ]; then
if [ -f "$PATH_TO_TRIGGER_FILES/*.control" ]; then
test_log_msg "test_SYSTEM" $NOTICE "Valid Maintenance Lock file found, test actions blocked." "status"
test_log_email " " " " " " "test Actions were blocked because an testLOCK file less than 24hrs old is in place." " "
else
test_log_msg "test_SYSTEM" $NOTICE "Valid Maintenance Lock file in place." "status"
exit
fi
fi
但是,当我使用“set -x trap read debug”单步执行代码行时,出现以下错误:
+ '[' find /var/opt/test/maintenancelock/testLOCK -mtime -1 ']'
/opt/test/test_control.sh: line 72: [: too many arguments
有办法在这里做我想做的事吗?
答案1
Try help [
then help test
--[
是 的同义词test
,test
帮助中说:
测试的行为取决于参数的数量。
这样:[ find "$MAINTENANCE_LOCK/testLOCK" -mtime -1 ];
您将 4 个单词传递给[
,并且它不知道如何处理 4 个参数。
我正在尝试检查特定文件是否存在(但仅当存在时间少于 24 小时时),如果存在,则执行第二次检查以查看名称以“.control”结尾的文件是否存在。
使用bash:
mapfile -t testlock < <(find "$MAINTENANCE_LOCK/testLOCK" -mtime -1)
if [[ ${#testlock[@]} -eq 0 ]]; then
echo "lock file does no exist or is too old"
else
control=( "$PATH_TO_TRIGGER_FILES/"*.control )
if [[ ${#control[@]} -gt 0 ]]; then
echo "lock file exists and at least one control file exists"
else
echo "lock file exists but no control files exist"
fi
fi
答案2
默认情况下,find
无论是否找到匹配的文件,始终返回 true (0)。
但是,使用-exec
谓词在匹配文件上运行/bin/false
,如果找到一个或多个匹配项,您可以让它返回 false (1)。测试其否定 ( !
) 如果找到则为 true,否则为 false。
例如:
# does the lock file exist?
if ! find "$MAINTENANCE_LOCK/testLOCK" -mtime -1 -exec false {} + ; then
# are there any .control files?
if ! find "$PATH_TO_TRIGGER_FILES" -name '*.control' -exec false {} + ; then
test_log_msg "test_SYSTEM" $NOTICE "Valid Maintenance Lock file found, test actions blocked." "status"
test_log_email " " " " " " "test Actions were blocked because an testLOCK file less than 24hrs old is in place." " "
else
test_log_msg "test_SYSTEM" $NOTICE "Valid Maintenance Lock file in place." "status"
exit
fi
fi
如果您经常这样做,或者只是希望您的脚本更具可读性/自文档化,您可以将其包装在一个函数中:
file_exists () {
# The args to this function are passed directly to find,
# so anything that works with find will work here.
# And anything that breaks find will break this function too.
# Also, you probably don't want to use any find arguments that
# produce any output.
if ! find "$@" -exec false {} + ; then
# one or more matching files were found, return true
return 0
else
# nothing found, return false
return 1
fi
}
if file_exists "$MAINTENANCE_LOCK/testLOCK" -mtime -1 ; then
if file_exists "$PATH_TO_TRIGGER_FILES" -name '*.control' ; then
...
else
...
fi
fi
请注意,/bin/false
完全忽略它的参数,它只返回 false (1) 的退出代码,无论它有多少个参数......所以如果您只需要测试是否存在但这是有用的不是如果你需要的话很有用数数匹配文件的数量。如果您需要这样做,您可以执行类似的操作(使用 GNU find 或任何其他支持的 find -printf
):
if [ "$(find . -mtime -1 -printf 1 | wc -c)" -gt 10 ] ; then
: do something here
fi
这会为找到的每个文件打印一个字符(打印哪个字符并不重要 - 我在这里使用“1”,但对于“.”或“x”或任何其他字符,它的工作方式相同),并且然后用 来计算它们wc -c
。如果超过 10 个,则if
测试评估为 true。
find
对于不-printf
支持(也是非 POSIX,但仍然很常见)选项的非 GNU -print0
,您可以使用:
if [ "$(find . -mtime -1 -print0 | awk -v RS='\0' 'END{print NR}')" -gt 10 ] ; then
: do something here
fi
该版本用于在的输出awk
中打印 NUL 分隔的记录数(即匹配文件的数量) 。find
如果您绝对确定没有任何文件或目录名中的任何一个将包含换行符 ( \n
) 字符,那么您可以使用 POSIX 标准-print
而不是-print0
(并通过管道输入wc -l
) - 但这永远不是您可以依赖的东西,因为您永远无法真正绝对确定这样的文件名在将来的某个时刻将永远不会存在。也就是说,它最多可能现在有效,但明天或明年可能会失败。
答案3
该find
命令应该返回几个文件,因此您会看到警告。
如果你想检查一个文件,最好使用stat
file_btime=$(stat -c%W /var/opt/test/maintenancelock/testLOCK)
time_now=$(date %s)
file_age=$(( time_now - file_btime ))
if [ $file_age -le 86400 ] ; then
echo File is less then 24h old
fi