【问题标题】:How to grep text patterns from remote crontabs using xargs through SSH?如何通过 SSH 使用 xargs 从远程 crontabs grep 文本模式?
【发布时间】:2022-02-02 19:10:59
【问题描述】:

我正在开发一个脚本来搜索从 CRON 通过 SSH 在一堆远程服务器上执行的脚本中的模式。

Script on client machine -- SSH --> Remote Servers CRON/Scripts

目前我无法获得正确的输出。

客户端机器上的脚本

#!/bin/bash
server_list=( '172.x.x.x' '172.x.x.y' '172.x.x.z' )
for s in ${server_list[@]}; do
    ssh -i /home/user/.ssh/my_key.rsa user@${s} crontab -l | grep -v '^#\|^[[:space:]]*$' | cut -d ' ' -f 6- | awk '{print $1}' | grep -v '^$\|^echo\|^find\|^PATH\|^/usr/bin\|^/bin/' | xargs -0 grep -in 'server.tld\|10.x.x.x'
done

这只会给我来自 crontab 的脚本路径,而不是匹配的行和行号加上第一行以“grep:”关键字为前缀(示例如下):

grep: /opt/directory/script1.sh
/opt/directory/script2.sh
/opt/directory/script3.sh
/opt/directory/script4.sh

如何获得正确的输出,即脚本路径加上行号加上匹配模式的行?

远程 CRON 示例

OO 6 * * * /opt/directory/script1.sh foo 
30 6 * * * /opt/directory/script2.sh bar

远程脚本内容示例

1 ) 这将匹配 grep 模式

#!/bin/bash
ping -c 4 server.tld && echo "server.tld ($1)"

2 ) 这与 grep 模式不匹配

#!/bin/bash
ping -c 4 8.x.x.x && echo "8.x.x.x ($1)"

【问题讨论】:

  • 我不知道它应该做什么。哪些部分应该在远程计算机上执行,哪些部分应该在本地执行?目前只有crontab -l远程运行,其余管道在本地。此外,xargs -0 仅在其输入以 null 分隔时才有意义(这就是 -0 的含义),而 grep 的输出则不会。
  • @gordon-davisson:我需要获取由远程 crontab 触发的脚本的内容,当然只有那些匹配 grep 搜索模式(server.tld 或 10.x.x.x)的脚本跨度>

标签: linux bash ssh grep xargs


【解决方案1】:

没有示例输入,很难看出您的脚本试图做什么。但是cron 解析几乎肯定可以通过将其全部重构为单个 Awk 脚本而大大简化。这是一个快速的刺,显然没有办法测试。

#!/bin/sh
# No longer using an array for no good reason, so /bin/sh will work
for s in 172.x.x.x 172.x.x.y 172.x.x.z; do
    ssh -i /home/user/.ssh/my_key.rsa "user@${s}" crontab -l |
    awk '! /^#|^[[:space:]]*$/ && $6 !~ /^$|^(echo|find|PATH|\/usr\/bin|\/bin\/)/ { print $6 }' |
    # no -0; use grep -E and properly quote literal dot
    xargs grep -Ein 'server\.tld|10.x.x.x'
done

您的命令不会将空分隔的数据输出到xargs,因此可能直接的问题是xargs -0 会将所有文件名作为一个显然不存在的文件名接收,并且您忘记包含“ : file not found" 从错误消息的末尾开始。

grep -E 的使用是一个小技巧,可以启用更现代的正则表达式语法,它与 Awk 中的语法更相似,您不必反斜杠“或”管道等。

此脚本与您的原始脚本一样,在您运行 SSH 脚本的本地系统上运行 grep。如果要在远程服务器上运行命令,则需要重构以将整个管道放在单引号或此处的文档中:

for s in 172.x.x.x 172.x.x.y 172.x.x.z; do
    ssh -i /home/user/.ssh/my_key.rsa "user@${s}" <<\________HERE
        crontab -l |
        awk '! /^#|^[[:space:]]*$/ && $6 !~ /^$|^(echo|find|PATH|\/usr\/bin|\/bin\/)/ { print $6 }' |
        xargs grep -Ein 'server\.tld|10.x.x.x'
________HERE
done

重构后的脚本在引用中包含足够的复杂性,您可能不想将其作为参数传递给ssh,这需要您弄清楚如何在本地和远程引用字符串。将其作为标准输入传递会更容易,这显然只是逐字传输。

如果你得到“伪终端将不会被分配,因为标准输入不是终端。”,尝试使用ssh -t。有时您需要添加多个-t 选项才能完全摆脱此消息。

【讨论】:

  • awk 部分触发“未终止的正则表达式”错误
  • 这就是为什么提供minimal reproducible example 很重要,但是是的,感谢您的反馈;固定。
  • 已经提供了示例,问题出在命令的 awk 部分
  • 感谢您的更新,但仍不清楚,例如文件应该放在哪里。您想在安装了cron 作业的系统上运行grep,还是在本地运行?
  • 是的,请参阅 CRON 示例和脚本内容示例
猜你喜欢
  • 1970-01-01
  • 2012-06-18
  • 1970-01-01
  • 2018-09-09
  • 2014-01-20
  • 1970-01-01
  • 2017-08-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多