.NET REDIRECTSTANDARDOUTPUT和REDIRECTSTANDARDINPUT重叠

发布于 2025-01-17 21:49:04 字数 3433 浏览 4 评论 0原文

我正在编写一个原型应用程序,该应用程序需要将命令行应用程序的stdin和stdout流重定向到其他应用程序,以及它的作品。但是,有一些令人讨厌的行为,我似乎无法奏效。标准输入流写入的任何内容也出现在标准输出流中。

以命令提示为例,我将在标准输入流中写下以下内容:

C:\Users\Me>echo Hello

然后在标准图上,我阅读以下内容:

echo Hello
Hello

有关更多示例:

C:\Users\Me>ls
ls
'ls' is not recognized as an internal or external command, operable program or batch file. 
C:\Users\Me>whoami
whoami
domain\Me
C:\Users\Me>NonSensicalCommand fooArgs fooArg1 forArg2 ImAlittleTeapot
NonSensicalCommand fooArgs fooArg1 forArg2 ImAlittleTeapot 
'NonSensicalCommand' is not recognized as an internal or external command, operable program or batch file.

这似乎是通用的,即我重定向流的任何应用程序。我尝试使用CMD,PLINK和一些我写的个人CLI项目。标准输入中写入的任何内容和所有内容始终显示在标准输出中。

我可以做的事情可以使这两个流保持分开吗?我已经尝试从诸如“ Echo Off”之类的事情开始,但这并没有完成任何事情。

以下是我的代码(同样,以CMD为例;用PLINK运行,交换PSI线)

using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;

static void Main( string[ ] args )
{
    ProcessStartInfo psi = new ProcessStartInfo( "C:\\Windows\\System32\\cmd.exe" );

    // If you'd like to run the code with the Plink, use the below line instead
    //ProcessStartInfo psi = new ProcessStartInfo( "C:\\Program Files\\PuTTY\\plink" ,
    //"-ssh [email protected] -pw FooPass" );

    psi.RedirectStandardInput = true;
    psi.RedirectStandardOutput = true;
    psi.WindowStyle = ProcessWindowStyle.Normal;
    psi.UseShellExecute = false;
    psi.CreateNoWindow = false;

    Process process = new Process( );
    process.StartInfo = psi;
    process.Exited += Process_Exited;
    process.EnableRaisingEvents = true;
    process.Start( );
    process.StandardInput.NewLine = "\n"; // using \r\n causes confusion in the Unix environment; just use \n
    process.StandardInput.AutoFlush = true;

    // [Lines 30 -> 42] Async Routine constantly reads stdout and prints to screen; reads a sinlge byte, then reads again.
    AsyncCallback stdOutCallback = null;
    byte[ ] myBuffer = new byte[1];

    stdOutCallback = asyResult =>
    {
        int bytesRead = process.StandardOutput.BaseStream.EndRead( asyResult );

        Console.Write( Encoding.ASCII.GetString( myBuffer ) );

        process.StandardOutput.BaseStream.BeginRead( myBuffer, 0, 1, stdOutCallback, null );
    };
    
    process.StandardOutput.BaseStream.BeginRead( myBuffer, 0, 1, stdOutCallback, null );
    
    
    // Writing to StandardInput exists inside a dedicated thread which will be handed the process
    new Thread( WriteToInput ).Start( process );
    
    // Wait for controlled process to exit
    process.WaitForExit( );
}

// Raisable event; current application exits with the same exit code as connected process
static void Process_Exited( object sender, EventArgs e )
{
    Environment.Exit( ((Process)sender).ExitCode );
}

// Constant loop which reads console input and writes it to connected process StandardInput
static void WriteToInput( object targ )
{
    Process process = (Process)targ;
    
    string input = Console.ReadLine( );
    
    while ( input != "---" )
    {
        process.StandardInput.WriteLine( input );
        input = Console.ReadLine( );
    }
}

I am writing a prototype application that will require redirecting the stdin and stdout streams of a command-line application to a different application, and it kind of works. However, there is some annoying behavior which I cannot seem to work around. Anything written to the StandardInput stream also appears in the StandardOutput stream.

Using command prompt as an example, I would write, the following into the StandardInput stream:

C:\Users\Me>echo Hello

and then on StandardOutput, I read the following:

echo Hello
Hello

For more examples:

C:\Users\Me>ls
ls
'ls' is not recognized as an internal or external command, operable program or batch file. 
C:\Users\Me>whoami
whoami
domain\Me
C:\Users\Me>NonSensicalCommand fooArgs fooArg1 forArg2 ImAlittleTeapot
NonSensicalCommand fooArgs fooArg1 forArg2 ImAlittleTeapot 
'NonSensicalCommand' is not recognized as an internal or external command, operable program or batch file.

This seems to be universal, to any application where I redirect the streams. I have tried with cmd, Plink, and some personal CLI items I've written. Anything and everything written to StandardInput always shows up in StandardOutput.

Is there something I can do which would keep these two streams separate? I've tried starting with things like "echo off", but that doesn't accomplish anything.

The following is my code (again, using cmd as an example; to run with plink, swap the PSI lines)

using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;

static void Main( string[ ] args )
{
    ProcessStartInfo psi = new ProcessStartInfo( "C:\\Windows\\System32\\cmd.exe" );

    // If you'd like to run the code with the Plink, use the below line instead
    //ProcessStartInfo psi = new ProcessStartInfo( "C:\\Program Files\\PuTTY\\plink" ,
    //"-ssh [email protected] -pw FooPass" );

    psi.RedirectStandardInput = true;
    psi.RedirectStandardOutput = true;
    psi.WindowStyle = ProcessWindowStyle.Normal;
    psi.UseShellExecute = false;
    psi.CreateNoWindow = false;

    Process process = new Process( );
    process.StartInfo = psi;
    process.Exited += Process_Exited;
    process.EnableRaisingEvents = true;
    process.Start( );
    process.StandardInput.NewLine = "\n"; // using \r\n causes confusion in the Unix environment; just use \n
    process.StandardInput.AutoFlush = true;

    // [Lines 30 -> 42] Async Routine constantly reads stdout and prints to screen; reads a sinlge byte, then reads again.
    AsyncCallback stdOutCallback = null;
    byte[ ] myBuffer = new byte[1];

    stdOutCallback = asyResult =>
    {
        int bytesRead = process.StandardOutput.BaseStream.EndRead( asyResult );

        Console.Write( Encoding.ASCII.GetString( myBuffer ) );

        process.StandardOutput.BaseStream.BeginRead( myBuffer, 0, 1, stdOutCallback, null );
    };
    
    process.StandardOutput.BaseStream.BeginRead( myBuffer, 0, 1, stdOutCallback, null );
    
    
    // Writing to StandardInput exists inside a dedicated thread which will be handed the process
    new Thread( WriteToInput ).Start( process );
    
    // Wait for controlled process to exit
    process.WaitForExit( );
}

// Raisable event; current application exits with the same exit code as connected process
static void Process_Exited( object sender, EventArgs e )
{
    Environment.Exit( ((Process)sender).ExitCode );
}

// Constant loop which reads console input and writes it to connected process StandardInput
static void WriteToInput( object targ )
{
    Process process = (Process)targ;
    
    string input = Console.ReadLine( );
    
    while ( input != "---" )
    {
        process.StandardInput.WriteLine( input );
        input = Console.ReadLine( );
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文