【问题标题】:Capture ALL (stdout, stderr AND CON) output of cmd executing plink with C# (std out+err ok, CON not working)捕获使用 C# 执行 plink 的 cmd 的所有(stdout、stderr AND CON)输出(std out+err ok,CON 不工作)
【发布时间】:2012-01-23 07:10:17
【问题描述】:

我想通过打开一个进程并运行 plink 从 c# 打开 SSH 连接。应该收集所有输出,并且根据结果,程序将向 ssh 触发操作。 我的大问题是,如果我使用不同的脚本,我需要(自动)用户交互。因此我必须捕获所有输出数据(标准输出、标准错误和控制台)。

看下面的测试批次应该会让案例更清楚:

1: @ECHO OFF
2: ECHO StdOut
3: ECHO StdErr 1>&2
4: ECHO Cons>CON

代码如下:

Process process;
Process process;
process = new Process();
process.StartInfo.FileName = @"cmd.exe";
process.StartInfo.Arguments = "/c test.bat";
process.StartInfo.UseShellExecute = false;
process.StartInfo.ErrorDialog = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardInput = true;
process.Start();
process.OutputDataReceived += new DataReceivedEventHandler(process_OutputDataReceived);
process.ErrorDataReceived += new DataReceivedEventHandler(process_OutputDataReceived);
process.BeginOutputReadLine();
process.BeginErrorReadLine();
StreamWriter inputWriter = process.StandardInput;
[...]

我能够捕获第 2+3 行,但不能捕获第 4 行(某些程序使用)。 我也尝试过 powershell(或直接 plink)而不是 cmd.exe 作为起点,但结果相同。

c# 中是否有任何方法可以捕获控制台,或者您是否知道任何第三方命令行能够将 CON 重定向到 stdout 或类似的东西?

【问题讨论】:

  • 标准输出和控制台有什么区别?
  • @DanielHilgarth 对于 Windows,我不完全确定,但在 UNIX 上,标准输出会定向到任何地方(包括文件或无处),而另一个总是会转到(文本模式)控制台。例如,这表明,如果您是远程登录的。控制台输出总是到物理控制台/计算机(我认为也有一些选项可以改变它,但一般来说)。

标签: c# shell redirect console capture


【解决方案1】:

我不确定这是否可行——至少不使用一些简单的 API。

请注意,我在网络上没有找到(尽管我尝试过)任何直接证实的信息,但这是我得出这个结论的原因。

Windows 中的控制台是它自己的子系统,由csrss.exe 管理(从Windows Vista 开始也有conhost.exe,但我离题了)。它有自己的一套 API(AttachConsoleWriteConsole 等),每个进程只能有一个“控制台”。

另一方面,CMD.EXE 只是另一个控制台模式应用程序,它恰好使用控制台并在控制台窗口中启动它。您可以通过启动不同的控制台模式应用程序并观察进程树来观察这种效果,例如进程资源管理器:没有 CMD.EXE 父进程(而是资源管理器或您用来启动它的任何东西 - 当然包括 CMD.EXE)。

到目前为止,我试图展示“控制台”和CMD.EXE、批处理文件或一般的控制台模式应用程序之间的区别。

因此,当您在CMD.EXE 中使用> CON 时,实际上会产生与在本机应用程序中写入CONOUT$ 相同的效果(或在类UNIX 操作系统上对/dev/console 的典型写入)。托管代码似乎没有直接的等价物,因为 Console.OutConsole.Error 在本机应用程序中等于 stdoutstderr(或 12 作为 CMD.EXE 中的文件描述符) .

话虽如此,当您启动一个进程时,您只能重定向它的标准输出和标准错误流,而不是(本身)它写入控制台(或CONOUT$ 句柄)的消息。我想这与尝试将进程写入某个文件的输出重定向相同,这也是(通常)不可能的。

您可以使用一些挂钩或在子进程中注入一些东西来获取控制台输出来实现这一点。

无法轻松做到这一点,也是(其中一个)为什么编写一个完整的终端(即控制台窗口,而不是CMD.EXE!)替换 Windows 并不容易并且需要一些技巧或解决方法。

【讨论】:

    【解决方案2】:

    AFAIK 知道你想要什么(重定向 CON)只能通过挂钩/注入来实现,这相当复杂,基本上不需要进行 SSH。

    对于 SSH,您可以使用任意数量的 C# 库(免费和商业):

    使用库的主要优点是您对 SSH 会话的控制比通过某些重定向控制台所能实现的要大得多,而且实现起来要容易得多...

    更新 - 根据 cmets:

    要从远程运行的程序中获取所有输出,您需要使用一个库,该库带有一个用于 SSH 的“交互式/终端”类 - 例如 http://www.rebex.net/ssh-pack/default.aspx 的库带有这样一个类并且工作得非常好(不是附属,只是一个快乐的客户),它可以用作纯代码组件或可视化控件(任何适合您的需求)。

    【讨论】:

    • +1“更容易实现......”并且可能更健壮。
    • 已经试过SharpSSH,但也只支持std和err out,不支持console out。会测试 sshnet,但不是很乐观(稍后会告诉你结果)。 “不需要”取决于所需的东西。我需要一个程序来自动在带有控制台“gui”的程序中进行用户交互,这只会写入屏幕而不是流。
    • @Yahia:我需要远程运行程序的输出。最后,这意味着我需要与在 cmd.exe 提示符上使用 plink 相同的输出(“我在 Windows 中看到的内容”),然后在这个 ssh 会话中进行交互
    • @MichaelK。请参阅上面的更新。
    • 终于我管理了我需要的东西,关键字“终端”成功了。 codeproject.com/Articles/13422/… 提供了一个 ssh 终端并添加一些代码可以捕获整个屏幕的输出。非常感谢您的详细回答,让我朝着正确的方向前进!
    【解决方案3】:

    以下是一些执行此操作的 CodeProject 项目(通过本机代码),AFAICT 可以更好地处理重定向所有控制台输出:

    Universal Console Redirector

    Redirecting an arbitrary Console's Input/Output

    此外,freopen 命令允许程序重定向其流。但是,如果程序执行显式 WriteConsole() 我不确定是否可以重定向。

    【讨论】:

    猜你喜欢
    • 2021-08-31
    • 1970-01-01
    • 2012-02-29
    • 2011-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多