我目前正在研究一种解决方案,每当我的邮件服务器无法将文件传输到我的 ftp 服务器时,它都会通知我。(目前我的日志每晚轮换一次,并立即上传到单独的 ftp 服务器)
当前配置如下:
HOST="..."
USER="..."
PASS="..."
DIR="/var/log/maillogs/"
LATEST="$(ls -t $DIR | head -n 2 | tail-n 1)"
FILE=$(basename $LATEST)
error=$(ftp -n $HOST <<EOF
quote USER $USER
quote PASS $PASS
prompt
lcd /var/log/maillogs/
cd /home/MailLog
put $FILE
quit
EOF
)
if [ $(echo $error | grep "failed")=="failed" ]
then
*Sending Mail via sendmail*
fi
由于某种原因,if 条件总是返回 true,所以无论文件是否能够传输,我都会收到一封邮件。
有人知道,当传输日志失败时,我该如何更改 if 语句才能真正获取邮件?
我也尝试过 的方法
if [ $? -ne 0 ]
,但我不太清楚如何测试它是否真的有效。我尝试提供虚假 IP 或错误的用户登录,但这样做只会收到不同的错误。
答案1
[
是一个内置命令,遵循与其他命令相同的语法规则 - 参数必须用引号引起来并用空格分隔。
具体来说,运算符 like==
应为单独的参数,因此不能省略其周围的空格。如果省略,则不会将其解释为运算符 - 整个运算符将被解释为[ one_arg ]
单参数模式,[
当参数非空时,将返回成功。
[ $(echo $error | grep "failed") = "failed" ]
^ ^
(此外,操作符只是=
。虽然 bash 接受[ x == y ]
,但这是非标准的。)
此外,任何字符串扩展都$(...)
需要用引号引起来 - 否则它们会在空格处被分割,并可能成为多个参数(或更糟):
[ "$(echo "$error" | grep failed)" = failed ]
^ ^
尽管如此,你实际上[
根本不需要这里 - shell 的if
接受任何命令,因此您可以直接使用返回的退出状态grep
:
if echo "$error" | grep -qs failed; then
echo "It failed :("
fi
进行子字符串检查的另一种方法是case
块:
case $error in
*failed*)
echo "Fail :("
;;
*)
echo "Success!"
;;
esac
如果你的脚本专门使用 Bash(即如果它有#!/bin/bash
或类似的东西),你可以使用[[
关键字来简化它,做有一些特殊的语法规则——左边的参数实际上不需要用引号引起来,相等运算符是==
,但更有用的是右边的值可以是通配符比较:
if [[ $error == *failed* ]]; then
echo "Fail :("
fi
所有这些都与您的 shell 脚本有关,但说实话?完全抛弃 FTP 并将其替换为例如 SFTP(通过 SSH 运行,您很可能已经拥有它)。
HOST="..."
USER="..."
# no PASS, it uses your id_rsa
DIR="/var/log/maillogs/"
LATEST="$(ls -t $DIR | head -n 2 | tail-n 1)"
FILE=$(basename $LATEST)
scp -p "$LATEST" "$USER@$HOST:/home/MailLog/" || {
echo "Fail :("
}
更好的办法是,设置远程系统日志,例如使用 syslog-ng,这样就可以传输消息居住到服务器。