转义 bash 和 SSH 中的复杂命令行参数



我正在开发一个bash脚本来检索服务器列表的正常运行时间。 它只是从文件中读取并在服务器上执行远程命令。 有些服务器可能已经启动了很长时间,而有些服务器可能刚刚重新启动。 我正在使用非常简单的东西:

uptime | awk '{print $2,$3,$4}'

如果服务器至少运行了一天,则此方法有效,但如果服务器仅启动了几个小时,则正常运行时间的输出不包括工作日,并且仅使用小时:分钟格式。

发现了一些我非常喜欢的东西,但似乎无法在 ssh 命令中正确转义它,更不用说尝试在 bash 脚本中传递它了:

uptime | awk -F'( |,|:)+' '{d=h=m=0; if ($7=="min") m=$6; else {if ($7~/^day/) {d=$6;h=$8;m=$9} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes."}'

我已经尝试了几件事,但这对我来说应该有效,并且似乎无法弄清楚我错过了什么:

ssh user@IP "uptime | awk -F'( |,|:)+' '{d=h=m=0; if ($7=="min") m=$6; else {if ($7~/^day/) {d=$6;h=$8;m=$9} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes."}'"

我得到的输出是:

awk: {d=h=m=0; if ($7=="min") m=$6; else {if ($7~/^day/) {d=$6;h=$8;m=$9} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes."}
awk:                                            ^ backslash not last character on line

最后,我试图将其放入如下所示的bash脚本中:

while IFS= read -r server; do
    ssh -tt user@$server  "uptime command" < /dev/null >> /home/user/uptime
done < "$file"

只需将命令发送到 ssh 的标准输入:

cat <<'EOF' | ssh user@machine
uptime | awk -F'( |,|:)+' '{d=h=m=0; if ($7=="min") m=$6; else {if ($7~/^day/) {d=$6;h=$8;m=$9} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes."}'
EOF

在我看来,你逃避得太多了:

ssh user@IP "uptime | awk -F'( |,|:)+' '{d=h=m=0; if ($7=="min") m=$6; else {if ($7~/^day/) {d=$6;h=$8;m=$9} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes."}'"

我得到:

6 days, 11 hours, 21 minutes.

更新:

由于同一命令要发送到多个不同的远程主机,因此我建议将其保存到变量中以便于重用。

command="uptime | awk -F'( |,|:)+' '{d=h=m=0; if ($7=="min") m=$6; else {if ($7~/^day/) {d=$6;h=$8;m=$9} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes."}'"
ssh user@IP1 "$command"
ssh user@IP2 "$command"

试运转:

$ bash script.sh
0 days, 2 hours, 26 minutes.
7 days, 4 hours, 18 minutes.

等等,还有更多:

经常需要向远程主机发送多个命令:为此,我发现 choroba 在他的答案中建议的引用的 heredoc 语法是最方便的。

command=$(cat <<'EOF'
hostname
uptime | awk -F'( |,|:)+' '{d=h=m=0; if ($7=="min") m=$6; else {if ($7~/^day/) {d=$6;h=$8;m=$9} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes."}'
EOF
)
ssh user@IP1 "$command"
ssh user@IP2 "$command"

这是输出:

$ bash script.sh
server1
0 days, 2 hours, 26 minutes.
server2
7 days, 4 hours, 18 minutes.

最新更新