在远程主机(通过 Cron 的 SSH)上捕获的命令输出为空白

Captured output of command on remote host (SSH via Cron) is blank

下面是一个脚本,它通过 SSH 登录远程主机(Cisco IOS-XR 路由器)和 运行s 一个命令。这个想法是获取命令的结果(一个整数),以便它可以被 Cacti 绘制出来。 Cacti 运行每 5 分钟执行一次此脚本,当它 运行 是正常的轮询例程时:

#!/bin/bash

if [[ -z  ]]
then
    exit 1
fi

HOST=""
USER="cact-ssh-user"
TIMEOUT=10s
export SSHPASS="aaaaaaaaaaaaa"

CMD="show controllers np struct IPV4-LEAF-FAST-P np0 | in Entries"
RAW_OUTPUT=$(timeout $TIMEOUT sshpass -e ssh -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null $USER@$HOST "$CMD" 2>/dev/null)
GRT_UCASTV4_USED=$(echo -n "$RAW_OUTPUT" | grep "Entries" | awk '{print }' | tr -d "," | tr -d " ")

echo -n "ucastv4_used:$GRT_UCASTV4_USED"

这个命令通过交互式 shell 工作正常(当我 运行 Cacti 服务器上的脚本使用 /path/to/script/script.sh 10.0.0.1 时。但是当 Cacti cronjob 运行输出只是空白。所以在我与 Cacti 服务器的 SSH 会话中,输出是:

$ ./script 10.0.0.1
ucastv4_used:1234

在 Cacti 日志中,输出是:05/22/2017 03:35:21 PM - SPINE: Poller[0] Host[69] TH[1] DS[6837] SCRIPT: /opt/scripts/cacti-scripts/asr9001-get-tcam-ucast-usage.sh 10.0.0.1, output: ucastv4_used:

我已经 su 发给了 Cacti 用户,脚本工作正常。所以这似乎是特定于它的 运行nings 作为一个 cronjob,SSH 命令的输出被神奇地重定向到某个地方,我不知道在哪里或为什么。

为了尝试调试它,我在脚本中添加了以下行(直接在 #!/bin/bash 下)并等待 Cacti 5 分钟的轮询间隔到 运行(我可以在 Cacti 中看到每 5 分钟调用一次脚本时记录);

exec >/tmp/stdout.log 2>/tmp/stderr.log
set -x

stdout.log 仅包含与 cacti.log 相同的 ucastv4_used:stderr.log 文件包含远程 SSH 主机的登录标志,仅此而已。 SSH 输出到哪里去了?

我厌倦了将脚本中的 SSH 行更改为输出到文件,然后从那里读取:

timeout $TIMEOUT sshpass -e ssh -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null $USER@$HOST "$CMD" > /tmp/output 2>/dev/null
GRT_UCASTV4_USED=$(grep "Entries" /tmp/output | awk '{print }' | tr -d "," | tr -d " ")

文件 /tmp/output 为空,因此 GRT_UCASTV4_USED 变量也为空。 stdout.log 最终和以前一样:ucastv4_used:

我还尝试将 #!/bin/bash 更改为 #!/bin/bash -i 以强制进行交互式会话。如果我将 echo $PS1 添加到脚本中,我可以在 stdout.log 文件中看到设置了 $PS1 而没有设置 -i什么都不打印。但是,SSH 命令仍然没有输出。 SSH输出的命令去哪里了?

我也尝试过使用 ssh ..... | tee /tmp/output 以便输出显示在 /tmp/output/tmp/stdout.log 中,但两者都是空白的。

我可以在远程路由器上看到 SSH 会话正在进入并且 运行正在执行命令。这是来自 debug ssh server:

RP/0/RSP0/CPU0:May 22 14:52:57.976 UTC: SSHD_[65909]: (open_master_file) command added show controllers np struct IPV4-LEAF-FAST-P np0 | in Entries

此外,由于这是通过我与 Cacti 服务器的交互式会话进行的,我猜测问题出在此处而不是路由器。我也相信 Cacti 本身不是问题,我可以触发 spine 从我的交互式 SSH 会话中轮询该路由器主机并且脚本工作正常(进一步指出在非交互式 shell SSH 输出是 evaporating):

$ cd /usr/local/spine/bin
$ ./spine -V 7 69 69
...
05/22/2017 04:06:56 PM - SPINE: Poller[0] Host[69] TH[1] DS[6837] SCRIPT: /opt/scripts/cacti-scripts/asr9001-get-tcam-ucast-usage.sh 10.0.0.1, output: ucastv4_used:658809

所以似乎 SSH 输出被重定向到某个地方,我不能 "get it" 或者路由器以某种方式知道这是一个非交互式 SSH 客户端并且没有发送回任何东西。我还能如何调试它?

更新 1 在 Cisco 路由器上使用 debug ssh server 我捕获了调试日志,当我通过我的交互式 SSH 会话将脚本 运行 连接到 Cacti 服务器时,当它通过 Cacti 的轮询 运行 时 interval/cron 工作。我已经 diff 编辑了输出,我能找到的唯一有趣的外观差异(除了 SSH PID 更改和 Cacti 服务器的临时源端口更改等)如下:

*** 132,145 ****
   (sshd_interactive_shell) *** removing alarm
   sshd_interactive_shell - ptyfd = 46
   event_contex_init done
!  sshd_ptytonet - Channel 1 Received EOT (bytes:1)
!  sshd_ptytonet - Channel 1 exec command executed sending CHANNEL_CLOSE
!  (close_channel), pid:182260085, sig rcvd:1, state:10 chan_id:1
!  addrem_ssh_info_tuple: REMOVE Inside the critical Section %pid:182260085
!  Cleanup sshd process 182260085, session id 1, channel_id 1
!  addrem_ssh_info_tuple: REMOVE exiting the Critical Section %pid:182260085
   close_channel: Accounting stopped: scriptaccount
!  In delete channel code, pid:182260085, sig rcvd:1, state:10 chan_id:1
   Sending Exit Status: 0 sig: 1
   Sending Channel EOF msg
   Sending Channel close msg for remote_chan_id = 0 chan_id = 1
--- 134,147 ----
   (sshd_interactive_shell) *** removing alarm
   sshd_interactive_shell - ptyfd = 46
   event_contex_init done
!  Pad_len = 6, Packlen = 12
!  sshd_nettopty: EOF received. Disconnecting session
!  (close_channel), pid:182329717, sig rcvd:1, state:10 chan_id:1
!  addrem_ssh_info_tuple: REMOVE Inside the critical Section %pid:182329717
!  Cleanup sshd process 182329717, session id 1, channel_id 1
!  addrem_ssh_info_tuple: REMOVE exiting the Critical Section %pid:182329717
   close_channel: Accounting stopped: scriptaccount
!  In delete channel code, pid:182329717, sig rcvd:1, state:10 chan_id:1
   Sending Exit Status: 0 sig: 1
   Sending Channel EOF msg
   Sending Channel close msg for remote_chan_id = 0 chan_id = 1

上半部分是我与 Cacti 服务器的交互会话。我在 top hald sshd_ptytonet - Channel 1 Received EOT (bytes:1) 中注意到,而通过 cronjob,调试显示 sshd_nettopty: EOF received. Disconnecting session。非交互式会话是否只是将我的 SSH 命令传递给远程主机并尽快退出(因此它不会等待 SSH 服务器响应命令输出)?

  • 首先,告诉 SSH 客户端不要分配带有 -T 选项的 PTY,因为显然 cron 没有。
  • 然后在 stdin 上给它一些无限的东西,所以它将保持 运行 直到 stdout 是开放的,我们有 /dev/zero 正是为此目的。

RAW_OUTPUT=$(timeout $TIMEOUT sshpass -e ssh -T -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null $USER@$HOST "$CMD" </dev/zero 2>/dev/null)