2009-09-14 46 views
20

tôi cần sử dụng bash shell "bên trong" chương trình C#. Tôi muốn bắt chước gõ người dùng ở chế độ tương tác và chạy lệnh Cygwin.Sử dụng bash (cygwin) bên trong chương trình C#

tôi đã tạo một quy trình chạy bash và chuyển hướng stdin, lỗi stout và std nhưng tôi không thể làm việc được đính kèm là mã mẫu bắt đầu quá trình bash và chuyển hướng đầu vào/đầu ra.

vấn đề là tôi không có thiết bị tty. nếu tôi cố gắng chạy lệnh tty hoặc lệnh stty tôi nhận được phản ứng lỗi

tty - not a tty 
stty - Inappropriate ioctl for device 

tôi nghĩ rằng điều này là do từ psi.UseShellExecute = false;

tôi cần phải chạy Cygwin và vô hiệu hóa tiếng vang với stty -echo nhưng để làm i này cần một thiết bị tty. làm thế nào ca tôi tạo ra một vỏ bash Cygwin với thiết bị tty và chuyển hướng các stdin, ra và lỗi?

1) những gì còn thiếu?

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); 
      } 
     } 
    } 
} 
+0

Tôi đã chạy chương trình của bạn và mặc dù tôi thấy lỗi "ioctl cho thiết bị không phù hợp", tôi cũng thấy dấu nhắc bash Cygwin sau đó. Chính xác thì vấn đề là gì? Tôi đã loại bỏ đường CYGWIN = tty và tôi thấy rằng đầu ra te là thô, với các mã điều khiển được hiển thị. –

+0

@Hemlock - Tôi nghĩ chìa khóa ở đây, dựa trên câu trả lời của Kevin Mark, là bạn có thể quyết định có sử dụng tiếng vọng hay không, vì vậy nó có thực sự quan trọng nếu bạn tắt tiếng/etc ... Và động lực là gì để cố lừa CYGWIN vào việc sử dụng TTY? – Peter

Trả lời

2

Một lưu ý phụ, không phải là một câu trả lời thực tế, có một cái nhìn tại địa chỉ: http://www.codeproject.com/KB/IP/sharpssh.aspx

Để trả lời câu hỏi:

của bạn không xử lý một cách chính xác các sự kiện ... Bạn cần phải tìm kiếm e .Data == null trong xử lý sự kiện cho Lỗi/đầu ra nhận được. Khi cả hai trình xử lý sự kiện nhận sự kiện này VÀ quá trình đã chấm dứt bạn đã hoàn tất. Vì vậy, bạn chờ đợi trên ba xử lý, một để cho bạn biết sự kiện Process.Exited bị sa thải, một để cho bạn biết đầu ra lỗi nhận được null, một để cho bạn biết đầu ra nhận được null. Hãy chắc chắn cũng để thiết lập:

process.EnableRaisingEvents = true; 

Dưới đây là câu trả lời đầy đủ chuyển hướng đầu ra đến console hiện tại:

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; 
    } 
+0

vấn đề là tôi không có thiết bị tty. nếu tôi cố gắng chạy tty lệnh hoặc stty lệnh tôi nhận được phản ứng lỗi tty - không phải là một tty stty - ioctl không phù hợp cho thiết bị tôi nghĩ rằng điều này là do từ psi.UseShellExecute = false; tôi cần chạy Cygwin và vô hiệu hóa echo với stty -echo nhưng để làm điều này tôi cần một thiết bị tty. làm thế nào ca tôi tạo ra một vỏ bash Cygwin với thiết bị tty và chuyển hướng stdin, ra và lỗi? –

+0

Vấn đề của bạn là stty -echo cố gắng đặt cài đặt trên thiết bị đầu cuối nhưng khi bạn chuyển hướng stdout sang một đường ống khác, lệnh này sẽ bị lỗi. Mã chuyển hướng của csharptest.net không hoạt động cho bạn nhưng việc chuyển hướng và thiết lập các công cụ liên quan đến giao diện điều khiển ngăn cản lẫn nhau. Bạn nên thay đổi skript được gọi là của bạn để phát hiện trường hợp đầu ra được chuyển hướng, ví dụ: bằng cách chỉ cần gọi stty -echo để kiểm tra xem bạn có được chuyển hướng hay không. –

6

này có thể hoặc không có thể giúp bạn hay bất cứ ai khác người xảy ra qua câu hỏi này. Đây là câu trả lời cho cùng một câu hỏi chính xác trên danh sách gửi thư của 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

Nguồn: http://www.cygwin.com/ml/cygwin/2009-09/msg00637.html

0

Chỉ exec cái gì đó như:

C:\cygwin\bin\bash -li /cygdrive/c/<path-to-shell-script-location>/chmod-cmd.sh 

Và sau đó bám vào các đầu vào và đầu ra.

HOẶC sử dụng mintty.

Các vấn đề liên quan