Windows 有多个内置选项可用于访问远程计算机的 shell(命令提示符)并在该远程计算机上运行命令。这是通过远程计算机上的 Windows 远程管理服务 (winrm) 完成的,可以通过winrs -r:<remote address>
(cmd) 或Enter-PSSession -ComputerName <remote address>
(PowerShell) 从客户端访问。我可以使用这两种方法,并且可以在远程计算机上执行命令,就像我坐在它前面一样。
问题是,命令的输出显然不是“实时”或交互显示的,而是仅在命令执行完成后才显示。例如,dir /P
在大型目录上使用应该在每个文件名屏幕后暂停,并在按键后继续。在会话中winrs
,/P 参数将被忽略,目录列表将一次性全部转储。另一个示例是用于监视的 python 脚本,它无限期运行(直到手动停止)并定期更新屏幕(即清除屏幕并打印新信息)。当通过远程 shell 运行时,运行时不会显示输出,但只有在我手动中止它后,它才会获取最新的输出。
当远程命令/程序运行时,第三方 SSH 连接(例如 Bitvise SSH 服务器和 putty 客户端)可以完美地进行实时更新。有没有办法让 Windows 中的内置远程 shell 具有相同的行为?我特别指的是 Windows 10,但它也适用于旧版本,至少可以追溯到 Win 7。
答案1
问题在于,命令的输出显然不是“实时”或交互显示的,而是在命令执行完毕后才显示的。例如,在大型目录上使用 dir /P 应该在显示每个文件名屏幕后暂停,并在按下键盘后继续。在 winrs 会话中,/P 参数将被忽略,目录列表将一次性全部转储。
这实际上是两个不同的问题。
WinRS 和 PSRP 协议确实能够以增量方式传输命令输出,并且发送输入例如,如果你曾经del /p
删除过文件,你会已经看到确认提示。
他们没有提供的是安慰具有明确定义的宽度×高度——相反,输出是通过“管道”捕获的。因此,dir
命令本身假定它以非交互方式运行并决定忽略您的/p
选项并且首先不显示任何提示,类似于您使用 时所得到的提示dir /p > list.txt
。
(这是通过同一个 WinRM 连接传输的两个不同的 API - “winrs”命令使用“远程 Shell”(WinRS),而 Enter-PSSession 使用“PowerShell Remoting”(PSRP) - 但它们具有相同的限制,即它们只能提供流输入但不能提供完整的控制台访问。)
SSH 服务器,包括 Windows 10 附带的“OpenSSH for Windows”服务器,做为远程程序创建一个控制台,这就是让它ssh -t localhost "dir /p"
工作的原因——因为它现在知道意图(它没有被重定向到文件或某些东西)并且还识别每页需要显示的行数(SSH 服务器将远程控制台配置为与本地控制台大小相同)。
大多数程序运行时(包括 Python)都会在内部缓冲其输出,并且只有在积累了一定量后才会将其刷新到操作系统。它们中的大多数还会根据输出所连接的内容调整缓冲 - 就像在 Linux 上一样,如果 Python 检测到其 sys.stdout 是终端,它将使用基于行的缓冲(写入后立即刷新输出\n
),但在写入文件或管道时,它将使用基于块的缓冲(仅每 8 kB 数据刷新一次)。
使用print(..., flush=True)
或调用sys.stdout.reconfigure(line_buffering=True)
可能会对你的情况有所帮助,尽管它仍然不允许程序清除屏幕或接收复杂输入(例如箭头键)。你仍然需要 SSH 来实现这一点。