방법 : C #에서 명령 줄 실행, STD OUT 결과 가져 오기


472

C #에서 명령 줄 프로그램을 실행하고 STD OUT 결과를 다시 얻으려면 어떻게해야합니까? 특히 프로그래밍 방식으로 선택된 두 파일에서 DIFF를 실행하고 결과를 텍스트 상자에 쓰고 싶습니다.


2
stackoverflow.com/a/5367686/492 도 참조하십시오 -출력 및 오류에 대한 이벤트를 보여줍니다.
CAD bloke

관련 (그러나 STDOUT을 캡처하지 않고) : stackoverflow.com/questions/1469764
user202729

답변:


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();

코드는 MSDN 에서 가져온 것 입니다.


8
배치 파일 없이이 작업을 수행 할 수 있습니까? 그것은 일부 매개 변수를 명령에 보내야한다는 것입니다. xsd.exe <Assembly> / type : <ClassName>을 사용하고 있으므로 Assembly와 ClassName을 모두 설정 한 다음 명령을 실행해야합니다.
Carlo

26
{YourProcessObject}.StartInfo.Arguments문자열을 통해 호출에 인수를 추가 할 수 있습니다 .
patridge

5
프로세스를 관리자 권한으로 실행하는 방법
Saher Ahwal

5
프로세스가 p.StandardError스트림에 충분한 데이터를 작성했기 때문에이 코드를 사용하는 프로세스가 완전히 중지되는 많은 문제가 발생했습니다 . 스트림이 가득 차면, 데이터가 소모 될 때까지 모두 읽을 필요하므로 프로세스가 중단 것으로 보인다 StandardErrorStandardOutput작업이 제대로 실행하는 보장하기 위하여한다.
테드 스펜스

5
c # 컴파일러의 빠른 헤드 업 : IO 스트림을 리디렉션하려면 Process 객체에 UseShellExecute 속성이 false로 설정되어 있어야합니다.
IbrarMumtaz

144

다음은 간단한 샘플입니다.

//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
명령 행 프로그램 실행에 인수를 추가하는 방법을 보여주는 +1 (허용 된 답변에는 없음)
Suman

104

프로세스 창을 제거하는 데 유용한 다른 매개 변수가 있습니다.

pProcess.StartInfo.CreateNoWindow = true;

원하는 경우 사용자에게 검은 색 콘솔 창을 완전히 숨기는 데 도움이됩니다.


3
나에게 많은 두통을 저장했다. 감사.
Vivandiere

2
"sc"를 호출 할 때 StartInfo.WindowStyle = ProcessWindowStyle.Hidden도 설정해야했습니다.
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
매우 포괄적 인 예, 감사
ShahidAzim

2
stdOut.AppendLine ()에 OutputDataReceived 핸들러를 변경할 수 있습니다
폴 윌리엄스

3
제 생각에는 이것이 받아 들인 대답보다 훨씬 포괄적 인 솔루션입니다. 나는 지금 그것을 사용하고 있으며 허용되는 것을 사용하지는 않았지만 실제로는 부족한 것처럼 보입니다.
ProfK

1
덕분에 대해 process.StartInfo.RedirectStandardError = true;하고 if (process.ExitCode == 0)허용하는 대답이 없습니다.
JohnB

12

이 페이지에서 허용되는 답변은 드문 상황에서 문제가되는 약점을 가지고 있습니다. 프로그램이 표준, stdout 및 stderr로 쓰는 두 개의 파일 핸들이 있습니다. Ray의 응답과 같은 단일 파일 핸들을 읽고 시작하는 프로그램이 stderr에 충분한 출력을 쓰면 출력 stderr 버퍼 및 블록을 채 웁니다. 그런 다음 두 프로세스가 교착 상태가됩니다. 버퍼 크기는 4K 일 수 있습니다. 이것은 단기 프로그램에서는 극히 드물지만 stderr에 반복적으로 출력되는 장기 실행 프로그램이 있으면 결국 발생합니다. 디버깅 및 추적이 까다 롭습니다.

이것을 처리하는 몇 가지 좋은 방법이 있습니다.

  1. 한 가지 방법은 프로그램 대신 cmd.exe를 실행하고 cmd.exe에 대해 / c 인수를 사용하여 cmd.exe에 대한 "2> & 1"인수와 함께 프로그램을 호출하여 stdout과 stderr을 병합하도록 지시하는 것입니다.

            var p = new Process();
            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.Arguments = "/c mycmd.exe 2>&1";
    
  2. 또 다른 방법은 두 핸들을 동시에 읽는 프로그래밍 모델을 사용하는 것입니다.

            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
나는 이것이 C # (파일이 아닌)을 통해 CMD 명령을 실행하는 방법을 보여주기 때문에 원래의 질문에 더 잘 대답한다고 생각합니다.
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();
 }

프로세스가 많은 데이터를 쓸 때 교착 상태가 발생할 수 있습니다. 프로세스가 계속 실행되는 동안 데이터 읽기를 시작하는 것이 좋습니다.
JensG

6

당신은 사용해야합니다 ProcessStartInfo함께 RedirectStandardOutput다음 출력 스트림을 읽을 수 - 수있었습니다. ">"를 사용하여 출력을 파일로 리디렉션하고 (OS를 통해)보다 쉽게 ​​파일을 읽을 수 있습니다.

[편집 : 레이가 한 것처럼 : +1]


10
따라서 권한이 필요한 위치에 파일을 작성하고 위치와 이름을 찾아야하며 작업이 끝나면 삭제하는 것을 잊지 않아야합니다. RedirectStandardOutput실제로 사용하기 쉽습니다 .
peSHIr

4

의존성을 도입하지 않아도 CliWrap은이 를 단순화 시켜줍니다 .

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

3

이것은 가장 좋은 방법은 아니지만 옵션 일 수 있습니다.

코드에서 실행할 때 "> output.txt"를 추가 한 다음 output.txt 파일을 읽으십시오.


3

Process 클래스를 사용하여 명령 행 프로그램을 시작하고 작성한 스트림 리더 (문자열 또는 메모리 위치 기반)를 사용하여 Process 인스턴스의 StandardOutput 특성을 설정할 수 있습니다. 프로세스가 완료되면 해당 스트림에서 필요한 모든 차이를 수행 할 수 있습니다.


3

PC / 서버에서 로컬 ARP 캐시를 쿼리하려는 경우 누군가에게 유용 할 수 있습니다.

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

원 라이너 실행 명령 :

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

가장 짧은 양의 재 코드로 명령 출력을 읽으십시오.

    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

cmd.exe에서 일부 명령을 실행해야하는 경우 다음을 수행 할 수 있습니다.

// 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);

명령 자체의 출력 만 반환합니다.

여기에 이미지 설명을 입력하십시오

StandardInput대신에 사용할 수도 있습니다 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);

결과는 다음과 같습니다.

여기에 이미지 설명을 입력하십시오


0

재미있게, 여기에 버튼 클릭으로 오류보고와 함께 PYTHON 출력을 얻는 완성 된 솔루션이 있습니다. "butPython"이라는 버튼과 "llHello"라는 라벨을 추가하면됩니다.

    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

여기에있는 대부분의 답변은 usingstatemant를 구현하지 않기 때문에 IDisposable필자가 생각할 수있는 다른 것들을 추가 할 것입니다.

C # 8.0의 경우

// 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");
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.