如何通过 SSH 使用 xargs 从远程 crontabs 中获取文本模式?
How to grep text patterns from remote crontabs using xargs through SSH?
我正在开发一个脚本来搜索通过 SSH 在一堆远程服务器上从 CRON 执行的脚本中的模式。
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 }' | 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 ()"
2 ) 这与 grep 模式不匹配
#!/bin/bash
ping -c 4 8.x.x.x && echo "8.x.x.x ()"
如果没有示例输入,真的很难看出您的脚本试图做什么。但是 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:]]*$/ && !~ /^$|^(echo|find|PATH|\/usr\/bin|\/bin\/)/ { print }' |
# no -0; use grep -E and properly quote literal dot
xargs grep -Ein 'server\.tld|10.x.x.x'
done
您的命令不会将 null-delimited 数据输出到 xargs
所以可能直接的问题是 xargs -0
将所有文件名作为一个文件名接收,这显然不存在,并且您忘记在错误消息末尾包含“:未找到文件”。
grep -E
的使用是一个小技巧,可以启用更现代的正则表达式语法,它与 Awk 中的语法更相似,您不必反斜杠“或”管道等。
此脚本与您的原始脚本一样,运行s grep
在您 运行 SSH 脚本所在的本地系统上。如果您想 运行 远程服务器上的命令,您需要重构以将整个管道放在单引号或此处文档中:
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:]]*$/ && !~ /^$|^(echo|find|PATH|\/usr\/bin|\/bin\/)/ { print }' |
xargs grep -Ein 'server\.tld|10.x.x.x'
________HERE
done
重构后的脚本在引用中包含足够的复杂性,您可能不想将其作为参数传递给 ssh
,这需要您弄清楚如何在本地和远程引用字符串。然后将它作为标准输入传递更容易,这显然只是逐字传输。
如果出现“Pseudo-terminal 不会被分配,因为标准输入不是终端。”,请尝试使用 ssh -t
。有时您需要添加多个 -t
选项才能完全摆脱此消息。
我正在开发一个脚本来搜索通过 SSH 在一堆远程服务器上从 CRON 执行的脚本中的模式。
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 }' | 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 ()"
2 ) 这与 grep 模式不匹配
#!/bin/bash
ping -c 4 8.x.x.x && echo "8.x.x.x ()"
如果没有示例输入,真的很难看出您的脚本试图做什么。但是 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:]]*$/ && !~ /^$|^(echo|find|PATH|\/usr\/bin|\/bin\/)/ { print }' |
# no -0; use grep -E and properly quote literal dot
xargs grep -Ein 'server\.tld|10.x.x.x'
done
您的命令不会将 null-delimited 数据输出到 xargs
所以可能直接的问题是 xargs -0
将所有文件名作为一个文件名接收,这显然不存在,并且您忘记在错误消息末尾包含“:未找到文件”。
grep -E
的使用是一个小技巧,可以启用更现代的正则表达式语法,它与 Awk 中的语法更相似,您不必反斜杠“或”管道等。
此脚本与您的原始脚本一样,运行s grep
在您 运行 SSH 脚本所在的本地系统上。如果您想 运行 远程服务器上的命令,您需要重构以将整个管道放在单引号或此处文档中:
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:]]*$/ && !~ /^$|^(echo|find|PATH|\/usr\/bin|\/bin\/)/ { print }' |
xargs grep -Ein 'server\.tld|10.x.x.x'
________HERE
done
重构后的脚本在引用中包含足够的复杂性,您可能不想将其作为参数传递给 ssh
,这需要您弄清楚如何在本地和远程引用字符串。然后将它作为标准输入传递更容易,这显然只是逐字传输。
如果出现“Pseudo-terminal 不会被分配,因为标准输入不是终端。”,请尝试使用 ssh -t
。有时您需要添加多个 -t
选项才能完全摆脱此消息。