bash - 没有 -tt 的 stderr 的 ssh 缓冲问题
问题描述
我正在尝试使用输出到标准错误和标准输出的 ssh 远程运行 bash 脚本。
当我在终端中正常运行时,我会按顺序获得输出。但是当使用 ssh 运行时,我不会,例如:
$ ssh -T user@host bash <<< "echo hi >&2 && echo bye"
bye
hi
标准错误延迟到标准输出之后。这与我在网上看到的关于缓冲 stderr 和 stdout 之间的差异的大多数事情形成对比,这些差异表明 stderr 是无缓冲的(因此将首先输出)。
但无论如何,我尝试的几乎所有东西都无法让线条按顺序输出。我已经尝试将 stdbuf -e0 -o0 -i0 拍打到命令的几乎每个部分(在 ssh 之前,在 bash 之前,在 echo 之前)。我尝试了不同的方式来传递命令(有bash -c
,bash
根本没有)。
我发现,如果我将 -tt 传递给 ssh,我发现它似乎始终如一地工作的一种方法。但是使用 -tt 似乎会添加自己的蠕虫罐头,如果可能的话,我不希望这样做。
还有其他方法可以使 ssh 输出缓冲更“正常”吗?
解决方案
stderr 无缓冲仅意味着数据立即写入 fd,但它不能保证写入的数据何时由接收器(pty、socket、管道……)处理。
对于ssh -T
,请参阅此示例(在 Debian Linux 上):
[STEP 103] # ssh -T 127.0.0.1 'ls -l /proc/$$/fd'
total 0
lr-x------ 1 root root 64 Aug 4 13:59 0 -> pipe:[4610144]
l-wx------ 1 root root 64 Aug 4 13:59 1 -> pipe:[4610145]
l-wx------ 1 root root 64 Aug 4 13:59 2 -> pipe:[4610146]
lr-x------ 1 root root 64 Aug 4 13:59 3 -> /proc/23662/fd
[STEP 104] #
如图所示,sshd
使用 3 个管道与其子进程通信(这种方式sshd
能够区分 stdout 数据和 stderr 数据)。对于孩子来说,保证写入 stderr 的数据将立即发送到管道,但完全由sshd
进程决定何时处理数据。(更新:即使在sshd
将数据发送回ssh
客户端之后,仍然由ssh
客户端决定何时处理接收到的数据。)
至于ssh -tt
,将为孩子分配一个pty。子进程的stdin、stdout和stderr都会在pty上打开,sshd
无法区分stdour数据和stderr数据,所以结果是预期的。
要验证ssh -tt
无法区分 stdout 数据和 stderr 数据:
[STEP 109] # ssh -T 127.0.0.1 'echo hi; echo bye >&2'
hi
bye
[STEP 110] # ssh -T 127.0.0.1 'echo hi; echo bye >&2' 2> /dev/null
hi
[STEP 111] #
[STEP 112] # ssh -tt 127.0.0.1 'echo hi; echo bye >&2'
hi
bye
Connection to 127.0.0.1 closed.
[STEP 113] # ssh -tt 127.0.0.1 'echo hi; echo bye >&2' 2> /dev/null
hi
bye
[STEP 114] #
推荐阅读
- pandas - 删除第一个单词,然后将该单词作为索引,就像一个热编码向量 pandas
- c++ - 从文件加载 QImage 的优化
- git - Jenkins:为 Github Pull 请求构建合并提交
- laravel - Laravel 5.4 政策检查总是假的
- spring - Spring 支持 IntellIJ
- java - 如何在scala和java中反序列化json
- python - 2018年熊猫世界杯数据集净胜球
- python - 如何做numpy.sctype2char的倒退。将 char 转换为 dtypes 或 sctype
- django - 在 Django 中请求数据
- swift - 在 tableView 上搜索多个对象