在C#程序中使用bash(cygwin)
我需要使用bashshell“内部”C#程序。我想模拟用户在交互模式下键入并运行cygwin命令 我创建了一个运行bash和重定向stdin、stout和std error的进程,但我可以;t get tty to work attached是启动bash进程并重定向输入/输出的示例代码在C#程序中使用bash(cygwin),c#,bash,process,cygwin,C#,Bash,Process,Cygwin,我需要使用bashshell“内部”C#程序。我想模拟用户在交互模式下键入并运行cygwin命令 我创建了一个运行bash和重定向stdin、stout和std error的进程,但我可以;t get tty to work attached是启动bash进程并重定向输入/输出的示例代码 问题是我没有tty设备。如果我尝试运行tty命令或stty命令,我将收到错误响应 tty - not a tty stty - Inappropriate ioctl for device 我认为这是由于p
问题是我没有tty设备。如果我尝试运行tty命令或stty命令,我将收到错误响应
tty - not a tty
stty - Inappropriate ioctl for device
我认为这是由于psi.UseShellExecute=false代码>
我需要运行cygwin并使用stty-echo禁用echo,但要做到这一点,我需要一个tty设备。如何使用tty设备创建cygwin bash shell并重定向stdin、out和error
1) 我错过了什么
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
namespace shartCygwin
{
class Program
{
private static Queue<string> ResponseQueue = null;
private static ManualResetEvent ResponseEvent = null;
static void Main(string[] args)
{
ResponseQueue = new Queue<string>();
ResponseEvent = new ManualResetEvent(false);
Process bashProcess = new Process();
bashProcess.StartInfo.FileName = "C:\\cygwin\\bin\\bash.exe";
bashProcess.StartInfo.Arguments = "--login -i ";
bashProcess.StartInfo.WorkingDirectory = "C:\\cygwin\\bin";
bashProcess.StartInfo.EnvironmentVariables["CYGWIN"] = "tty";
bashProcess.StartInfo.RedirectStandardError = true;
bashProcess.StartInfo.RedirectStandardInput = true;
bashProcess.StartInfo.RedirectStandardOutput = true;
bashProcess.StartInfo.CreateNoWindow = true;
bashProcess.StartInfo.UseShellExecute = false;
bashProcess.StartInfo.ErrorDialog = false;
bashProcess.Start();
DataReceivedEventHandler errorEventHandler = new DataReceivedEventHandler(ErrorDataReceived);
DataReceivedEventHandler outEventHandler = new DataReceivedEventHandler(OutDataReceived);
bashProcess.OutputDataReceived += outEventHandler;
bashProcess.ErrorDataReceived += errorEventHandler;
bashProcess.BeginErrorReadLine();
bashProcess.BeginOutputReadLine();
while(true)
{
Thread.Sleep(1000);
}
}
static void ErrorDataReceived(object sender, DataReceivedEventArgs dataReceivedEventArgs)
{
try
{
lock (ResponseQueue)
{
Console.WriteLine(dataReceivedEventArgs.Data);
ResponseQueue.Enqueue(dataReceivedEventArgs.Data);
ResponseEvent.Set();
}
}
catch (Exception e)
{
Console.WriteLine(e.Data);
}
}
static void OutDataReceived(object sender, DataReceivedEventArgs dataReceivedEventArgs)
{
try
{
lock (ResponseQueue)
{
Console.WriteLine(dataReceivedEventArgs.Data);
ResponseQueue.Enqueue(dataReceivedEventArgs.Data);
ResponseEvent.Set();
}
}
catch (Exception e)
{
Console.WriteLine(e.Data);
}
}
}
}
使用系统;
使用System.Collections.Generic;
使用系统诊断;
使用System.Linq;
使用系统文本;
使用系统线程;
名称空间shartCygwin
{
班级计划
{
私有静态队列ResponseQueue=null;
专用静态手动重置事件响应事件=null;
静态void Main(字符串[]参数)
{
ResponseQueue=新队列();
ResponseEvent=新手动重置事件(假);
Process bashProcess=新流程();
bashProcess.StartInfo.FileName=“C:\\cygwin\\bin\\bash.exe”;
bashProcess.StartInfo.Arguments=“--login-i”;
bashProcess.StartInfo.WorkingDirectory=“C:\\cygwin\\bin”;
bashProcess.StartInfo.EnvironmentVariables[“CYGWIN”]=“tty”;
bashProcess.StartInfo.RedirectStandardError=true;
bashProcess.StartInfo.RedirectStandardInput=true;
bashProcess.StartInfo.RedirectStandardOutput=true;
bashProcess.StartInfo.CreateNoWindow=true;
bashProcess.StartInfo.UseShellExecute=false;
bashProcess.StartInfo.ErrorDialog=false;
bashProcess.Start();
DataReceiveDevenHandler errorEventHandler=新DataReceiveDevenHandler(ErrorDataReceived);
DataReceivedEventHandler outEventHandler=新的DataReceivedEventHandler(OutDataReceived);
bashProcess.OutputDataReceived+=outEventHandler;
bashProcess.ErrorDataReceived+=errorEventHandler;
bashProcess.BeginErrorReadLine();
bashProcess.BeginOutputReadLine();
while(true)
{
睡眠(1000);
}
}
静态无效错误DataReceived(对象发送方、DataReceivedEventArgs DataReceivedEventArgs)
{
尝试
{
锁(应答器)
{
Console.WriteLine(dataReceivedEventArgs.Data);
响应队列(dataReceivedEventArgs.Data);
ResponseEvent.Set();
}
}
捕获(例外e)
{
控制台写入线(如数据);
}
}
静态void OutDataReceived(对象发送方、DataReceivedEventArgs DataReceivedEventArgs)
{
尝试
{
锁(应答器)
{
Console.WriteLine(dataReceivedEventArgs.Data);
响应队列(dataReceivedEventArgs.Data);
ResponseEvent.Set();
}
}
捕获(例外e)
{
控制台写入线(如数据);
}
}
}
}
一个旁注,而不是真正的答案,看看:
要回答这个问题:
您没有正确处理事件。。。您需要在接收到的错误/输出的事件处理程序中查找e.Data==null。一旦两个事件处理程序都接收到此事件并且进程终止,您就完成了。因此,您需要等待三个句柄,一个告诉您流程。已触发Exited事件,一个告诉您错误输出接收null,一个告诉您输出接收null。请确保还设置:
process.EnableRaisingEvents = true;
以下是将输出重定向到当前控制台的完整答案:
static int RunProgram(string exe, params string[] args)
{
ManualResetEvent mreProcessExit = new ManualResetEvent(false);
ManualResetEvent mreOutputDone = new ManualResetEvent(false);
ManualResetEvent mreErrorDone = new ManualResetEvent(false);
ProcessStartInfo psi = new ProcessStartInfo(exe, String.Join(" ", args));
psi.WorkingDirectory = Environment.CurrentDirectory;
psi.RedirectStandardError = true;
psi.RedirectStandardOutput = true;
psi.CreateNoWindow = true;
psi.UseShellExecute = false;
psi.ErrorDialog = true;
Process process = new Process();
process.StartInfo = psi;
process.Exited += delegate(object o, EventArgs e)
{
Console.WriteLine("Exited.");
mreProcessExit.Set();
};
process.OutputDataReceived += delegate(object o, DataReceivedEventArgs e)
{
if( e.Data != null )
Console.WriteLine("Output: {0}", e.Data);
else
mreOutputDone.Set();
};
process.ErrorDataReceived += delegate(object o, DataReceivedEventArgs e)
{
if (e.Data != null)
Console.Error.WriteLine("Error: {0}", e.Data);
else
mreErrorDone.Set();
};
process.EnableRaisingEvents = true;
Console.WriteLine("Start: {0}", process.StartInfo.FileName);
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
if (process.HasExited)
mreProcessExit.Set();
while(!WaitHandle.WaitAll(new WaitHandle[] { mreErrorDone, mreOutputDone, mreProcessExit }, 100))
continue;
return process.ExitCode;
}
这可能会也可能不会帮助你或任何遇到这个问题的人。这是对Cygwin邮件列表上相同问题的答案
> i created a process that runs bash and redirect stdin,stout and std error
> but I can’t get tty to work attached is a sample code that starts bash
> process and redirect the input/output.
> the problem is that i don't have tty device. if i try to run tty command or
> stty command i receive error response
> tty - not a tty
> stty - Inappropriate ioctl for device
> i need to run cygwin and disable echo with stty -echo but to do this i need
> a tty device. how can i create a cygwin bash shell with tty device and
> redirect the stdin, out and error ?
Why exactly do you think you need to run stty and set the tty operating
parameters, when the bash process is quite plainly *not* connected to a tty,
it is connected to your C# application?
It's your application that is in charge of I/O - if it doesn't want echo,
all it has to do is discard the stuff it reads from the process' stdout
instead of displaying it, in your OutDataReceived/ErrorDataReceived handlers.
> bashProcess.StartInfo.EnvironmentVariables["CYGWIN"] = "tty";
Don't do this. Win32 native processes don't understand Cygwin's tty
emulation, which is based on pipes.
cheers,
DaveK
>我创建了一个运行bash和重定向stdin、stout和std error的进程
>但我无法让tty工作。附加的是启动bash的示例代码
>处理并重定向输入/输出。
>问题是我没有tty设备。如果我尝试运行tty命令或
>stty命令我收到错误响应
>tty-不是tty
>stty-设备的ioctl不正确
>我需要运行cygwin并使用stty-echo禁用echo,但要做到这一点,我需要
>一种轻巧的装置。如何使用tty设备和
>重定向标准输入、输出和错误?
为什么您认为您需要运行stty并将tty设置为运行状态
参数,当bash进程非常明显地*未*连接到tty时,
它是否连接到您的C#应用程序?
是您的应用程序负责I/O—如果它不需要echo,
它所要做的就是丢弃从进程stdout读取的内容
而不是在OutDataReceived/ErrorDataReceived处理程序中显示它。
>bashProcess.StartInfo.EnvironmentVariables[“CYGWIN”]=“tty”;
不要这样做。Win32本机进程不理解Cygwin的tty
基于管道的仿真。
干杯
达维克
来源:只需执行类似以下内容:
C:\cygwin\bin\bash -li /cygdrive/c/<path-to-shell-script-location>/chmod-cmd.sh
C:\cygwin\bin\bash-li/cygdrive/C//chmod-cmd.sh
然后锁定输入和输出
或者使用。问题是我没有tty设备。如果我尝试运行tty命令或stty命令,我会收到错误响应tty-不是tty stty-设备的ioctl不适当,我认为这是由psi.UseShellExecute=false引起的;我需要运行cygwin并使用stty-echo禁用echo,但要做到这一点,我需要一个tty设备。如何使用tty d创建cygwin bash shell