que - palabras claves del lenguaje c#
Usando bash(cygwin) dentro del programa C# (3)
Necesito usar el programa C # de bash shell "inside". Quiero imitar el tipeo del usuario en modo interactivo y ejecutar comandos de cygwin.
Creé un proceso que ejecuta bash y redirigir stdin, stout y std error pero no puedo obtener tty para trabajar adjunto. Es un código de muestra que inicia el proceso bash y redirige la entrada / salida.
el problema es que no tengo tty dispositivo. Si intento ejecutar el comando tty o el comando stty, recibo una respuesta de error
tty - not a tty
stty - Inappropriate ioctl for device
creo que esto es causado por psi.UseShellExecute = false;
Necesito ejecutar cygwin y desactivar echo con stty -echo pero para hacer esto necesito un dispositivo tty. ¿Cómo puedo crear un shell cygwin bash con dispositivo tty y redirigir el stdin, out y error?
1) ¿Qué me falta?
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);
}
}
}
}
Una nota al margen, no es una respuesta real, eche un vistazo a: http://www.codeproject.com/KB/IP/sharpssh.aspx
Para responder la pregunta:
No maneja correctamente los eventos ... Debe buscar e.Data == null en el controlador de eventos para Error / Salida recibida. Una vez que ambos manejadores de eventos reciban este evento Y el proceso haya terminado, ya terminaste. Por lo tanto, espera en tres controles, uno para indicarle el evento Proceso. Se activó el evento, uno para indicarle que la salida de error recibió nulo, uno para indicarle que la salida recibida es nula. Asegúrese de establecer también:
process.EnableRaisingEvents = true;
Aquí está la respuesta completa que redirige el resultado a la consola actual:
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;
}
Esto puede o no ayudarlo a usted o a cualquier otra persona que se encuentre con esta pregunta. Esta es la respuesta dada a la misma pregunta exacta en la lista de correo de 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
Fuente: http://www.cygwin.com/ml/cygwin/2009-09/msg00637.html
Simplemente ejecute algo así como:
C:/cygwin/bin/bash -li /cygdrive/c/<path-to-shell-script-location>/chmod-cmd.sh
Y luego enganche en la entrada y la salida.
O use mintty .