linux - SSH 命令输出中使用的 Grep 不返回 PIPESTATUS
问题描述
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"
扩展变量后完成的唯一处理是分词和文件通配。它不处理转义符、管道、重定向、命令分隔符等。因此,当您执行该命令时,它相当于执行:
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 操作部分。处理像|
和>
这样的元字符在此步骤中完成:
- 将标记解析为简单和复合命令(请参阅Shell 命令)。
扩展变量在下一步中完成:
由于在查找管道和重定向之后会发生变量扩展,因此这些操作不会在本地完成,它们将在 . 发送命令时在远程系统上完成ssh
。
推荐阅读
- android - 尝试执行时获取错误消息源代码与字节码不匹配
- javascript - 按属性值选择元素时的 JavaScript 转义引号
- typescript - 去掉_target属性后,在iframe下打开新的url
- css - 在 CSS 中跨 flexbox 容器对齐文本基线
- python - 如何用正则表达式删除句子开头的特殊字符?
- javascript - 将经纬度从 javascript 或 html 传递到 Django 视图
- wordpress - Wordpress 重置密码密钥不起作用
- javascript - 范围类中的 getvalues 方法存在问题
- python - 蟒蛇 | 使用“线程”在大文件中搜索时性能不佳
- python - Java 注册表单:com.mysql.cj.jdbc.exceptions.MysqlDataTruncation:数据截断:第 1 行的“图片”列数据太长