【问题标题】:Mail output with Bash Script使用 Bash 脚本的邮件输出
【发布时间】:2016-02-13 17:48:21
【问题描述】:

使用我生成的 SSH 密钥从主机 A SSH 到几台主机(现在只在下面列出一个),然后转到特定文件,grep 查找日期为昨天的特定单词 .. 然后我想通过电子邮件发送这个输出给我自己。

它正在发送一封电子邮件,但它给了我命令而不是命令的输出。

#!/bin/bash

HOST="XXXXXXXXXXXXXXXXXX, XXXXXXXXXXXXX"

DATE=$(date -d "yesterday")

INVALID=' cat /xxx/xxx/xxxxx | grep 'WORD' | sed 's/$/.\n/g' | grep "$DATE"'

COUNT=$(echo "$INVALID" | wc -c)

for x in $HOSTS

do
ssh BLA@"$x" $COUNT

if [ "$COUNT" -gt 1 ];
then

    EMAILTEXT=""
        if [ "$COUNT" -gt 1 ];
        then
                EMAILTEXT="$INVALID"
        fi
fi

done | echo -e "$EMAILTEXT" | mail XXXXXXXXXXX.com

【问题讨论】:

  • 代码格式(使用{}按钮),有意义的标题(简洁地反映你的问题,而不是情绪)。请注意,HOSTHOSTS 是不同的变量。不要使用, 作为分隔符,只使用空格。否则,您的第一个主机将是 XXXXXXXXXXXXXXXXXX,(带逗号)
  • 请看:shellcheck.net
  • 代码不工作并且没有做任何有用的事情是一种非常糟糕的方式来传达你想要它做的事情。

标签: linux bash email for-loop ssh


【解决方案1】:

这不是试图正确回答您的问题,但我认为您应该注意您的代码的一些基本问题。

INVALID=' cat /xxx/xxx/xxxxx | grep 'WORD' | sed 's/$/.\n/g' | grep "$DATE"'

这会将一个简单的字符串分配给变量INVALID。由于引用问题,s/$/.\n/g 根本没有被引用,并且可能会被 shell 破坏。 (你不能嵌套单引号——第一个单引号字符串从第一个引号延伸到下一个引号,然后WORD 在任何引号之外,然后是下一个单引号字符串,等等)

如果此时您的意图是将其作为命令执行,则您正在寻找命令替换;随着uselessness 的多层剥离,可能类似于

INVALID=$(sed -n -e '/WORD/!d' -e "/$DATE/s/$/./p" /xxx/xxx/xxxx)

它查找匹配WORD$DATE 的行并打印匹配并在末尾附加一个点——我相信这就是你的代码归结为的内容,但没有进一步了解这段代码应该做什么做,无法判断这是否是您真正需要的。

COUNT=$(echo "$INVALID" | wc -c)

这会为$COUNT 分配一个编号。使用INVALID 的静态定义,数字将始终为 62;但我想这实际上不是你想要的。

for x in $HOSTS    
do
  ssh BLA@"$x" $COUNT

这会尝试将该数字作为命令在多个远程主机上执行(除了循环结束 HOSTS 并且包含主机的变量仅命名为 HOST)。这不可能有用,除非您有一组名为自然数的命令,它们在这些远程主机上做一些有用的事情;但我认为可以安全地假设这不是这里应该发生的事情(如果是的话,绝对有必要在你的问题中解释这一点)。

  if [ "$COUNT" -gt 1 ];
  then

    EMAILTEXT=""
        if [ "$COUNT" -gt 1 ];
        then
                EMAILTEXT="$INVALID"
        fi
  fi

所以EMAILTEXT 要么是空字符串,要么是 INVALID 的值。您将其分配为上面的静态字符串,这可能是您直接问题的来源。但是,即使它以某种方式分配给本地主机上的命令,为什么还需要访问远程主机并在那里执行某些操作呢?还是您的意图实际上是在每个远程主机上执行命令并获取输出?

done | echo -e "$EMAILTEXT" | mail XXXXXXXXXXX.com

输入echo 完全没有意义,因为它不读取其标准输入。您可能应该在done 之后添加一个换行符;尽管可能更有用的安排是让您的循环产生输出,然后我们将其通过管道传输到mail

纯属推测,也许您真正想要的是以下内容。

for host in $HOSTS; do
    ssh BLA@"$host" sed -n -e '/WORD/!d' -e "/$DATE/s/$/./p" /xxx/xxx/xxxx |
    grep . || echo INVALID
done | mail XXXXXXXXXXX.com

如果您想检查是否有超过一行的输出(这是-gt 1 所建议的),那么这可能需要稍微复杂一些。

【讨论】:

    【解决方案2】:

    您的命令替换不起作用。你应该read up on how it works 但这里有问题:

    COUNT=$(echo "$INVALID" | wc -c)
    [...]
    ssh BLA@"$x" $COUNT
    

    应该是:

    COUNT_CMD="'${INVALID} | wc -c'"
    [...]
    COUNT=$(ssh BLA@"$x" $COUNT_CMD)
    

    这会将$INVALID 的值插入到字符串中,并将整个内容放在单引号中。 ssh 调用需要单引号,因此不会在脚本中而是在远程主机上评估管道。 (COUNT 更改为 COUNT_CMD 以提高可读性/清晰度。)

    编辑:

    我误读了问题,并已更正了我的答案。

    【讨论】:

    • 我尝试过这种方式,它在本地而不是在远程主机上执行该变量
    • @Obsolete01 哇,我误读了你的问题,我的错。我已经更正了我的答案。
    • @Obsolete01 您能否更具体地说明上述修改发生了什么?
    • 当我运行它时,它试图在本地 cat 那个文件,然后通过 SSH 连接到第一台主机,但什么也没做
    • @Obsolete01 您是否在INVALID 的定义中使用了反引号?因为单引号不适用于该字符串,因为它包含单引号。如果您无法找出问题所在,请链接到您修改过的脚本的 gist/pastebin。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-21
    • 1970-01-01
    • 2018-05-18
    • 1970-01-01
    • 2019-11-17
    • 2010-12-12
    相关资源
    最近更新 更多