SSH命令输出上使用的Grep不返回PIPESTATUS

时间:2019-04-23 18:02:40

标签: linux bash shell

Grep在脚本中不返回pipestatus,但在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]}?

1 个答案:

答案 0 :(得分:1)

您需要使用eval来处理$SSH_CMD,就像将其作为命令键入一样。

eval "$SSH_CMD"

扩展变量后唯一要做的处理是分词和文件遍历。它不处理转义符,管道,重定向,命令定界符等。因此,当您执行该命令时,它等效于执行:

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

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

其结果是,命令“ 2>&1 | grep ... will be sent to the remote host. This will execute the commands 2>&1 and grep ...`在服务器上而不是在客户端上通过管道传输也可以在服务器上完成。

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

data="foo | wc"
echo $data

这将按字面意义打印foo | wc,它将不会执行echo foo,然后将其通过管道传输到wc。但是,如果您这样做:

eval "echo $data"

它就像您写的一样

echo foo | wc

有关更多详细信息,请参见《 Bash手册》中的Shell Operation部分。在此步骤中完成对|>之类的元字符的处理:

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

扩展变量将在下一步完成:

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

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