【问题标题】:I/O redirection in ssh commandssh 命令中的 I/O 重定向
【发布时间】:2019-06-25 10:18:19
【问题描述】:

我写了一个 bash 脚本rm_remote_file.sh,它通过 ssh 连接到一组远程机器并删除一个文件。我在每个函数调用结束时使用& 并行运行这些命令,脚本如下所示:

#!/bin/bash

rm_remote_file() {
    echo "Removing file on node $1:"
    ssh $1 'rm ~/test_file'
}

for node in node1.com node2.com node3.com; do
    rm_remote_file $node &
done

当每个节点上都存在 test_file 时 - rm 命令成功 - 此脚本的输出为:

Removing file on node node1.com:
Removing file on node node2.com:
Removing file on node node3.com:

我更喜欢打印出每个主机名。但是,如果每个节点上不存在 test_file - rm 命令失败 - 此脚本的输出为:

rm: cannot remove ‘~/test_file’: No such file or directory
rm: cannot remove ‘~/test_file’: No such file or directory
rm: cannot remove ‘~/test_file’: No such file or directory

因此,此错误消息会抑制节点主机名的打印。我认为这种行为与 I/O 重定向有关,使用诸如 2>&1 之类的东西可以解决这个问题。但我想知道为什么 ssh 命令错误消息会抑制 echo 命令。

请注意,这只发生在 ssh 命令中,以下脚本仅删除一些本地文件,会同时输出“正在删除文件”和“没有此类文件或目录”。

#!/bin/bash

rm_file() {
    echo "Removing file..."
    rm ./$1
}

for file in test1 test2 test3 test4 test5; do
    rm_file $file &
done

【问题讨论】:

  • 这不是保证只发生在 ssh 上,在设置过程中会有更多的延迟,所以更有可能。在本地版本中,rm_file 函数仍被分叉并在后台运行,但echo 的发生与rm 的发生非常接近。对于远程版本,echorm 之间存在很大延迟,而ssh 传输是协商的。
  • @CharlesDuffy 为什么echossh 之间的大延迟会阻止echo 消息?我尝试在 remove-local-files 脚本中的 echorm ./$1 之间添加 sleep 5,但我仍然可以看到 echo 消息和 rm 错误消息。
  • 不会阻止消息,但这意味着您有更大的机会破坏订单,因此您之前打印了所有三个 Removing file on node $i 消息任何 rm 错误。还要记住,在ssh 的情况下,确切的延迟量会有所不同,因此echos 的顺序和rm 错误的顺序特别有可能被解耦。
  • (很清楚,我不相信消息曾经被阻止的问题中的说法,并且在看到@987654321之前不会相信@; 更有可能它们只是发生在您日志中的其他地方,在您不看的地方,因为它们下方的失败消息将它们推离了屏幕)。
  • 当我们根本不使用2>&1 时,我们在运行remove-remote-files 脚本时看不到echo 消息,但在运行remove-local- 时我们确实看到echo 消息文件脚本。

标签: bash ssh io-redirection


【解决方案1】:

将 2>&1 添加到 ssh 命令,该消息和错误保持顺序:

ssh $1 'rm ~/test_file' 2>&1

讨论后的解决方案:

rm_remote_file() {
    echo "Removing file on node $1: $( ssh $1 'rm ~/test_file' 2>&1 )"
}

【讨论】:

  • 我不确定是否有保证。 rm_remote_file 内部仍然有两个单独的命令写入其继承的标准输出,并且所有三个 echo 命令仍然可以在任何一个 ssh 写入其输出之前运行。
  • 我看到三个消息,然后打印出三个错误,无法找出哪个消息对应哪个错误。最重要的是,我的问题更多是关于为什么来自 ssh 命令的错误会阻止回显消息,而来自本地 rm 命令的错误不会。
  • @chepner 是的,你是对的:其他解决方案:echo "Removing file on node $1: $( ssh $1 'rm ~/test_file' 2>&1 )"
  • @Wiimm 这解决了订购问题并完成了工作。但是,我只是想了解为什么会发生以下情况:当我们使用旧脚本并且不在脚本中的任何地方使用2>&1 或遵循./remove-remote-files.sh 时,标准输出将被rm 标准错误阻止。但是当它在本地运行时,我们可以同时看到 stdout 和 stderr。
  • 如果没有2&>1,就会有输出队列:stderr 和 stdout。两者都由自己管理,即使在脚本结束时也是如此。所以一个队列的消息可以通过另一个队列。原因可能是不同进程的缓冲和处理。早期的2&>1 将stderr 重定向到stdout。在最后一个变体中,stderr 被集成到 stdout 中。
猜你喜欢
  • 2021-11-09
  • 1970-01-01
  • 2011-11-22
  • 1970-01-01
  • 2010-10-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多