linux - SSH 命令输出中使用的 Grep 不返回 PIPESTATUS

标签 linux bash shell

Grep 不会在脚本中返回管道状态,但会在 shell 中返回。

查看包含的脚本:

#!/usr/bin/env bash

function testSshConnection() {
  local SSH_CMD="ssh -o BatchMode=yes -o ConnectTimeout=3 $1@$2 2>&1 | grep \"Host key verification failed.\""
  echo "RUNNING: $SSH_CMD"
  $SSH_CMD
  PIPE_RESULT="${PIPESTATUS[0]} ${PIPESTATUS[1]}"
  echo "FUNCTION: PIPE_RESULT: ${PIPE_RESULT}"
  PIPE_RESULT_ARRAY=($PIPE_RESULT)
  PIPE0="${PIPE_RESULT_ARRAY[0]}"
  PIPE1="${PIPE_RESULT_ARRAY[1]}"
  local RC=${PIPE1:-$PIPE0}
  echo "Returning RC=$RC"
  return $RC
}

while ! testSshConnection root $1; do
  PIPE_RESULT="${PIPESTATUS[0]} ${PIPESTATUS[1]}"
  echo "WHILE: PIPE_RESULT: ${PIPE_RESULT}"  
  PIPE_RESULT_ARRAY=($PIPE_RESULT)
  PIPE0="${PIPE_RESULT_ARRAY[0]}"
  PIPE1="${PIPE_RESULT_ARRAY[1]}"
  WAIT=4
  echo "Waiting $SLEEP seconds for host $1 to be accessible on port 22"
  sleep $WAIT
done

exit

脚本输出:

~ $ /tmp/test.sh 46.101.7.220
RUNNING: ssh -o BatchMode=yes -o ConnectTimeout=3 root@46.101.7.220 2>&1 | grep "Host key verification failed."
Host key verification failed.
FUNCTION: PIPE_RESULT: 255
Returning RC=255
WHILE: PIPE_RESULT: 255
 Waiting 4 seconds for host 46.101.7.220 to be accessible on port 22
RUNNING: ssh -o BatchMode=yes -o ConnectTimeout=3 root@46.101.7.220 2>&1 | grep "Host key verification failed."
Host key verification failed.
FUNCTION: PIPE_RESULT: 255
Returning RC=255
WHILE: PIPE_RESULT: 255
...etc

在单独的 shell 中运行 ssh 命令的输出:

~ $ ssh -o BatchMode=yes -o ConnectTimeout=3 root@46.101.7.220 2>&1 | grep "Host key verification failed."
Host key verification failed.
~ $ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
255 0

为什么脚本中的 ssh 命令没有为 grep 命令返回 ${PIPESTATUS[1]}?

最佳答案

您需要使用 eval 来处理 $SSH_CMD,就好像它是作为命令键入的一样。

eval "$SSH_CMD"

扩展变量后完成的唯一处理是分词和文件通配。它不处理 ecapes、管道、重定向、命令定界符等。因此当您执行该命令时,它相当于执行:

ssh -o BatchMode=yes -o ConnectTimeout=3 root@46.101.7.220 '2>&1' '|' grep '"Host' key verification 'failed."'

我已经引用了命令中包含 shell 元字符的部分,以表明它们在扩展变量后没有被特殊处理。

结果是命令“2>&1 | grep ...将被发送到远程主机。这将执行命令2>&1grep ...` 在服务器上,而不是在客户端上,管道也在服务器上完成。

一个更简单的例子,试试这个:

data="foo | wc"
echo $data

这将打印foo | wc 从字面上看,它不会执行 echo foo 然后将其通过管道传递给 wc。但如果你这样做:

eval "echo $data"

它会像你写的一样

echo foo | wc

有关详细信息,请参阅 Shell Operation 部分在 Bash 手册中。 |> 等元字符的处理是在这一步中完成的:

  1. 将标记解析为简单和复合命令(参见 Shell Commands)。

扩展变量在下一步完成:

  1. 执行各种 shell 扩展(参见 Shell Expansions ),将扩展的标记分解为文件名列表(参见 Filename Expansion )以及命令和参数。

由于变量扩展发生在 寻找管道和重定向之后,这些操作不会在本地完成,它们将在 ssh< 发送命令时在远程系统上完成.

关于linux - SSH 命令输出中使用的 Grep 不返回 PIPESTATUS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55816985/

相关文章:

bash - 无法使用 curl : argument too long 将大文件发送到 elasticsearch

bash - 替换csv文件的多个值

bash - 返回一个月的最后一天

shell - 使 LDAP 搜索不显示 DN

python - 如何在基于 Django 的网页中嵌入 linux 终端?

linux - 线程的好用?

linux - 如何列出该脚本的输出路径?

java - 执行命令liquibase,相对路径和用户反馈

linux - Lucene 上打开的文件太多错误

在 Linux 上发布软件时要支持的 Linux 发行版/版本