Nasıl Yapılır: C # 'da komut satırı yürütme, STD OUT sonuçlarını alma


472

C # 'dan bir komut satırı programını nasıl yürütebilirim ve STD OUT sonuçlarını nasıl geri alabilirim? Özellikle, programlı olarak seçilen iki dosya üzerinde DIFF yürütmek ve sonuçları bir metin kutusuna yazmak istiyorum.


2
Ayrıca bkz. Stackoverflow.com/a/5367686/492 - çıktı ve hatalarla ilgili olayları gösterir.
CAD bloke

İlgili (ancak
STDOUT'u

Yanıtlar:


523
// Start the child process.
 Process p = new Process();
 // Redirect the output stream of the child process.
 p.StartInfo.UseShellExecute = false;
 p.StartInfo.RedirectStandardOutput = true;
 p.StartInfo.FileName = "YOURBATCHFILE.bat";
 p.Start();
 // Do not wait for the child process to exit before
 // reading to the end of its redirected stream.
 // p.WaitForExit();
 // Read the output stream first and then wait.
 string output = p.StandardOutput.ReadToEnd();
 p.WaitForExit();

Kod MSDN'den .


8
Bunu bir toplu iş dosyası olmadan yapmanın bir yolu var mı? Şey, komuta bazı parametreler göndermek gerekir. Xsd.exe <Assembly> / type: <ClassName> kullanıyorum, bu yüzden hem Assembly hem de ClassName ayarlamak ve sonra komutu çalıştırmak gerekir.
Carlo

26
{YourProcessObject}.StartInfo.ArgumentsDize yoluyla çağrınıza bağımsız değişkenler ekleyebilirsiniz .
patridge

5
Süreci yönetici olarak nasıl çalıştırırım?
Saher Ahwal

5
Sürecin yeterli veri yazdığı için işlemimin bu kodu kullanarak tamamen durduğu bir dizi sorunla karşılaştım p.StandardError. Akış dolduğunda, veri tüketilene kadar işlemin duracağı anlaşılıyor, bu yüzden her ikisini de okumalıyım StandardErrorve StandardOutputbir görevin doğru bir şekilde yürütülmesini garanti etmek için.
Ted Spence

5
C # derleyicisinden hızlı başlık: IO akışlarını yeniden yönlendirmek için Process nesnesinde UseShellExecute özelliği false olarak ayarlanmış olmalıdır.
IbrarMumtaz

144

İşte hızlı bir örnek:

//Create process
System.Diagnostics.Process pProcess = new System.Diagnostics.Process();

//strCommand is path and file name of command to run
pProcess.StartInfo.FileName = strCommand;

//strCommandParameters are parameters to pass to program
pProcess.StartInfo.Arguments = strCommandParameters;

pProcess.StartInfo.UseShellExecute = false;

//Set output of program to be written to process output stream
pProcess.StartInfo.RedirectStandardOutput = true;   

//Optional
pProcess.StartInfo.WorkingDirectory = strWorkingDirectory;

//Start the process
pProcess.Start();

//Get program output
string strOutput = pProcess.StandardOutput.ReadToEnd();

//Wait for process to finish
pProcess.WaitForExit();

2
Bir komut satırı programını çalıştırmaya nasıl argüman ekleyeceğinizi gösteren +1 (kabul edilen yanıtın sahip olmadığı.)
Suman

104

İşlem penceresini kaldırmak için kullandığım başka bir parametre de buldum

pProcess.StartInfo.CreateNoWindow = true;

bu, isterseniz istediğiniz siyah konsol penceresini kullanıcıdan tamamen gizlemeye yardımcı olur.


3
Bana çok fazla baş ağrısı kurtardı. Teşekkürler.
Vivandiere

2
"Sc" çağrılırken ben de StartInfo.WindowStyle = ProcessWindowStyle.Hidden ayarlamak zorunda kaldı.
Pedro

90
// usage
const string ToolFileName = "example.exe";
string output = RunExternalExe(ToolFileName);

public string RunExternalExe(string filename, string arguments = null)
{
    var process = new Process();

    process.StartInfo.FileName = filename;
    if (!string.IsNullOrEmpty(arguments))
    {
        process.StartInfo.Arguments = arguments;
    }

    process.StartInfo.CreateNoWindow = true;
    process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
    process.StartInfo.UseShellExecute = false;

    process.StartInfo.RedirectStandardError = true;
    process.StartInfo.RedirectStandardOutput = true;
    var stdOutput = new StringBuilder();
    process.OutputDataReceived += (sender, args) => stdOutput.AppendLine(args.Data); // Use AppendLine rather than Append since args.Data is one line of output, not including the newline character.

    string stdError = null;
    try
    {
        process.Start();
        process.BeginOutputReadLine();
        stdError = process.StandardError.ReadToEnd();
        process.WaitForExit();
    }
    catch (Exception e)
    {
        throw new Exception("OS error while executing " + Format(filename, arguments)+ ": " + e.Message, e);
    }

    if (process.ExitCode == 0)
    {
        return stdOutput.ToString();
    }
    else
    {
        var message = new StringBuilder();

        if (!string.IsNullOrEmpty(stdError))
        {
            message.AppendLine(stdError);
        }

        if (stdOutput.Length != 0)
        {
            message.AppendLine("Std output:");
            message.AppendLine(stdOutput.ToString());
        }

        throw new Exception(Format(filename, arguments) + " finished with exit code = " + process.ExitCode + ": " + message);
    }
}

private string Format(string filename, string arguments)
{
    return "'" + filename + 
        ((string.IsNullOrEmpty(arguments)) ? string.Empty : " " + arguments) +
        "'";
}

3
Çok kapsamlı bir örnek, teşekkürler
ShahidAzim

2
OutputDataReceived işleyicisini stdOut.AppendLine () olarak değiştirmek isteyebilir
Paul Williams

3
Bence bu, kabul edilen cevaptan çok daha kapsamlı bir çözüm. Şimdi kullanıyorum ve kabul edileni kullanmadım, ama gerçekten eksik görünüyor.
ProfK

1
Teşekkür process.StartInfo.RedirectStandardError = true;ve if (process.ExitCode == 0)hangi kabul edilen cevaba sahip değil.
JohnB

12

Bu sayfadaki kabul edilen cevap, nadir durumlarda zahmetli bir zayıflığa sahiptir. Programların kongre, stdout ve stderr ile yazdığı iki dosya tanıtıcısı vardır. Ray'ın yanıtı gibi tek bir dosya tanıtıcısı okuduysanız ve başlattığınız program stderr'a yeterli çıktı yazarsa, çıktı stderr arabelleğini ve bloğunu dolduracaktır. Sonra iki süreciniz kilitlenir. Arabellek boyutu 4K olabilir. Bu, kısa ömürlü programlarda son derece nadirdir, ancak sürekli olarak stderr'e çıktı veren uzun bir programınız varsa, sonunda gerçekleşecektir. Bu hata ayıklamak ve izlemek için zor.

Bununla başa çıkmanın birkaç iyi yolu var.

  1. Bunun bir yolu, program yerine cmd.exe'yi çalıştırmak ve cmd.exe'ye / c bağımsız değişkenini kullanarak, programınızı stdout ve stderr birleştirmesini söylemek için cmd.exe'ye "2> & 1" bağımsız değişkeniyle birlikte çağırmaktır.

            var p = new Process();
            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.Arguments = "/c mycmd.exe 2>&1";
    
  2. Başka bir yol, her iki tutamacı aynı anda okuyan bir programlama modeli kullanmaktır.

            var p = new Process();
            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.Arguments = @"/c dir \windows";
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardInput = false;
            p.OutputDataReceived += (a, b) => Console.WriteLine(b.Data);
            p.ErrorDataReceived += (a, b) => Console.WriteLine(b.Data);
            p.Start();
            p.BeginErrorReadLine();
            p.BeginOutputReadLine();
            p.WaitForExit();
    

2
Ben bir CMD komut C # (bir dosya değil) üzerinden nasıl çalışacağını gösterir, bu özgün soruya daha iyi cevap düşünüyorum.
TinyRacoon

12
 System.Diagnostics.ProcessStartInfo psi =
   new System.Diagnostics.ProcessStartInfo(@"program_to_call.exe");
 psi.RedirectStandardOutput = true;
 psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
 psi.UseShellExecute = false;
 System.Diagnostics.Process proc = System.Diagnostics.Process.Start(psi); ////
 System.IO.StreamReader myOutput = proc.StandardOutput;
 proc.WaitForExit(2000);
 if (proc.HasExited)
  {
      string output = myOutput.ReadToEnd();
 }

İşlem çok fazla veri yazdığında kilitlenebilir. İşlem devam ederken verileri okumaya başlamak daha iyidir.
JensG

6

Sen kullanmanız gerekecektir ProcessStartInfoile RedirectStandardOutputo zaman çıkış akışı okuyabilir - sağladı. Çıktıyı bir dosyaya (işletim sistemi aracılığıyla) yönlendirmek için ">" kullanmayı daha kolay bulabilir ve ardından dosyayı okuyabilirsiniz.

[değiştir: Ray'in yaptığı gibi: +1]


10
Bu, sizi izin vermeniz gereken bir yere bir dosya yazmaya, bir konum ve bir ad bulmaya zorlar ve işiniz bittiğinde silmeyi unutmamalısınız. RedirectStandardOutputAslında kullanımı daha kolay .
peSHIr

4

Bir bağımlılık getirmenin bir sakıncası yoksa, CliWrap bunu sizin için basitleştirebilir:

var cli = new Cli("target.exe");
var output = await cli.ExecuteAsync("arguments", "stdin");
var stdout = output.StandardOutput;

3

Bu en iyi / en kolay yol olmayabilir, ancak bir seçenek olabilir:

Kodunuzdan yürüttüğünüzde, "> output.txt" ekleyin ve sonra output.txt dosyasında okuyun.


3

Process sınıfını kullanarak herhangi bir komut satırı programını başlatabilir ve oluşturduğunuz akış okuyucu ile Process örneğinin StandardOutput özelliğini ayarlayabilirsiniz (bir dize veya bellek konumuna göre). İşlem tamamlandıktan sonra, bu akışta ihtiyacınız olan her şeyi yapabilirsiniz.


3

Bir PC / Sunucu üzerindeki yerel ARP önbelleğini sorgulamaya çalışıyorsanız, bu birisi için yararlı olabilir.

List<string[]> results = new List<string[]>();

        using (Process p = new Process())
        {
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.Arguments = "/c arp -a";
            p.StartInfo.FileName = @"C:\Windows\System32\cmd.exe";
            p.Start();

            string line;

            while ((line = p.StandardOutput.ReadLine()) != null)
            {
                if (line != "" && !line.Contains("Interface") && !line.Contains("Physical Address"))
                {
                    var lineArr = line.Trim().Split(' ').Select(n => n).Where(n => !string.IsNullOrEmpty(n)).ToArray();
                    var arrResult = new string[]
                {
                   lineArr[0],
                   lineArr[1],
                   lineArr[2]
                };
                    results.Add(arrResult);
                }
            }

            p.WaitForExit();
        }

3

Tek astarlı çalıştırma komutu:

new Process() { StartInfo = new ProcessStartInfo("echo", "Hello, World") }.Start();

Komut çıktısını en kısa sürede okunabilir kod olarak okuyun:

    var cliProcess = new Process() {
        StartInfo = new ProcessStartInfo("echo", "Hello, World") {
            UseShellExecute = false,
            RedirectStandardOutput = true
        }
    };
    cliProcess.Start();
    string cliOut = cliProcess.StandardOutput.ReadToEnd();
    cliProcess.WaitForExit();
    cliProcess.Close();

2

Bir ProcessHelper Sınıf içinde bulunmaktadır kamu malı İlginizi çekebilir açık kaynak kodu.


2

Ayrıca cmd.exe içinde bazı komutları yürütmeniz gerekirse, aşağıdakileri yapabilirsiniz:

// Start the child process.
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/C vol";
p.Start();
// Read the output stream first and then wait.
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
Console.WriteLine(output);

Bu sadece komutun kendi çıktısını döndürür:

resim açıklamasını buraya girin

Şunlar StandardInputyerine şunları da kullanabilirsiniz StartInfo.Arguments:

// Start the child process.
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "cmd.exe";
p.Start();
// Read the output stream first and then wait.
p.StandardInput.WriteLine("vol");
p.StandardInput.WriteLine("exit");
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
Console.WriteLine(output);

Sonuç şuna benzer:

resim açıklamasını buraya girin


0

Sadece eğlence için, PYTHON çıktısını almak için tamamlanmış çözümüm - tek bir tıklama ile - hata raporlaması "ButPython" adında bir düğme ve "llHello" adında bir etiket eklemeniz yeterlidir ...

    private void butPython(object sender, EventArgs e)
    {
        llHello.Text = "Calling Python...";
        this.Refresh();
        Tuple<String,String> python = GoPython(@"C:\Users\BLAH\Desktop\Code\Python\BLAH.py");
        llHello.Text = python.Item1; // Show result.
        if (python.Item2.Length > 0) MessageBox.Show("Sorry, there was an error:" + Environment.NewLine + python.Item2);
    }

    public Tuple<String,String> GoPython(string pythonFile, string moreArgs = "")
    {
        ProcessStartInfo PSI = new ProcessStartInfo();
        PSI.FileName = "py.exe";
        PSI.Arguments = string.Format("\"{0}\" {1}", pythonFile, moreArgs);
        PSI.CreateNoWindow = true;
        PSI.UseShellExecute = false;
        PSI.RedirectStandardError = true;
        PSI.RedirectStandardOutput = true;
        using (Process process = Process.Start(PSI))
            using (StreamReader reader = process.StandardOutput)
            {
                string stderr = process.StandardError.ReadToEnd(); // Error(s)!!
                string result = reader.ReadToEnd(); // What we want.
                return new Tuple<String,String> (result,stderr); 
            }
    }

0

Buradaki en cevaplar, usingstatemant IDisposableve nessecary olabileceğini düşündüğüm diğer bazı şeyleri uygulamadığından, bu yanıtı ekleyeceğim.

C # 8.0 için

// Start a process with the filename or path with filename e.g. "cmd". Please note the 
//using statemant
using myProcess.StartInfo.FileName = "cmd";
// add the arguments - Note add "/c" if you want to carry out tge  argument in cmd and  
// terminate
myProcess.StartInfo.Arguments = "/c dir";
// Allows to raise events
myProcess.EnableRaisingEvents = true;
//hosted by the application itself to not open a black cmd window
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.CreateNoWindow = true;
// Eventhander for data
myProcess.Exited += OnOutputDataRecived;
// Eventhandler for error
myProcess.ErrorDataReceived += OnErrorDataReceived;
// Eventhandler wich fires when exited
myProcess.Exited += OnExited;
// Starts the process
myProcess.Start();
//read the output before you wait for exit
myProcess.BeginOutputReadLine();
// wait for the finish - this will block (leave this out if you dont want to wait for 
// it, so it runs without blocking)
process.WaitForExit();

// Handle the dataevent
private void OnOutputDataRecived(object sender, DataReceivedEventArgs e)
{
    //do something with your data
    Trace.WriteLine(e.Data);
}

//Handle the error
private void OnErrorDataReceived(object sender, DataReceivedEventArgs e)
{        
    Trace.WriteLine(e.Data);
    //do something with your exception
    throw new Exception();
}    

// Handle Exited event and display process information.
private void OnExited(object sender, System.EventArgs e)
{
     Trace.WriteLine("Process exited");
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.