Runtime.exec를 호출 할 때 stdout 캡처
클라이언트 컴퓨터에서 네트워킹 문제가 발생했을 때 몇 개의 명령 줄을 실행하고 그 결과를 자신에게 이메일로 보낼 수 있기를 바랍니다.
Runtime.exec를 사용하면 임의의 명령을 실행할 수 있지만 결과를 문자열로 수집하는 것이 더 흥미 롭습니다.
출력을 파일로 리디렉션 한 다음 파일에서 읽을 수 있다는 것을 깨달았지만 제 정신은 좀 더 우아한 방법이 있다고 말합니다.
제안?
프로세스에서 표준 출력과 표준 오류를 모두 캡처해야합니다. 그런 다음 std를 파일 / 메일 등에 쓸 수 있습니다.
자세한 내용은 이 문서 를 참조하세요. 특히 StreamGobbler
별도의 스레드에서 stdout / err을 캡처 하는 메커니즘에 유의하세요 . 이것은 차단을 방지하는 데 필수적이며 제대로 수행하지 않으면 수많은 오류의 원인이됩니다!
ProcessBuilder를 사용하십시오 . start ()를 호출 하면 stderr 및 stdout 스트림을 가져올 수있는 Process 객체를 얻게됩니다.
업데이트 : ProcessBuilder는 더 많은 제어를 제공합니다. 사용할 필요는 없지만 장기적으로는 더 쉽습니다. 특히 stderr을 stdout으로 리디렉션하는 기능은 하나의 스트림 만 흡입하면됩니다.
Plexus Utils를 사용하면 Maven에서 모든 외부 프로세스를 실행하는 데 사용됩니다.
Commandline commandLine = new Commandline();
commandLine.setExecutable(executable.getAbsolutePath());
Collection<String> args = getArguments();
for (String arg : args) {
Arg _arg = commandLine.createArg();
_arg.setValue(arg);
}
WriterStreamConsumer systemOut = new WriterStreamConsumer(console);
WriterStreamConsumer systemErr = new WriterStreamConsumer(console);
returnCode = CommandLineUtils.executeCommandLine(commandLine, systemOut, systemErr, 10);
if (returnCode != 0) {
// bad
} else {
// good
}
많은 출력을 생성하지 않는 프로세스의 경우 Apache IOUtils 를 활용하는이 간단한 솔루션 으로 충분 하다고 생각합니다 .
Process p = Runtime.getRuntime().exec("script");
p.waitFor();
String output = IOUtils.toString(p.getInputStream());
String errorOutput = IOUtils.toString(p.getErrorStream());
주의 사항 : 그러나 프로세스가 많은 출력을 생성하는 경우이 접근 방식은 Process 클래스 JavaDoc에 언급 된대로 문제를 일으킬 수 있습니다 .
생성 된 하위 프로세스에는 자체 터미널 또는 콘솔이 없습니다. 모든 표준 io (예 : stdin, stdout, stderr) 작업은 3 개의 스트림 (getOutputStream (), getInputStream (), getErrorStream ())을 통해 상위 프로세스로 리디렉션됩니다. 상위 프로세스는 이러한 스트림을 사용하여 하위 프로세스에 입력을 공급하고 출력을 가져옵니다. 일부 네이티브 플랫폼은 표준 입력 및 출력 스트림에 대해 제한된 버퍼 크기 만 제공하기 때문에 입력 스트림을 즉시 쓰거나 하위 프로세스의 출력 스트림을 읽지 못하면 하위 프로세스가 차단되고 교착 상태가 될 수도 있습니다.
이것은 몇 년 동안 사용했던 도우미 클래스입니다. 하나의 소규모 수업. JVM 리소스 누수를 수정하는 JavaWorld streamgobbler 클래스가 있습니다. JVM6 및 JVM7에 여전히 유효한지 모르겠지만 아프지는 않습니다. 도우미는 나중에 사용하기 위해 출력 버퍼를 읽을 수 있습니다.
import java.io.*;
/**
* Execute external process and optionally read output buffer.
*/
public class ShellExec {
private int exitCode;
private boolean readOutput, readError;
private StreamGobbler errorGobbler, outputGobbler;
public ShellExec() {
this(false, false);
}
public ShellExec(boolean readOutput, boolean readError) {
this.readOutput = readOutput;
this.readError = readError;
}
/**
* Execute a command.
* @param command command ("c:/some/folder/script.bat" or "some/folder/script.sh")
* @param workdir working directory or NULL to use command folder
* @param wait wait for process to end
* @param args 0..n command line arguments
* @return process exit code
*/
public int execute(String command, String workdir, boolean wait, String...args) throws IOException {
String[] cmdArr;
if (args != null && args.length > 0) {
cmdArr = new String[1+args.length];
cmdArr[0] = command;
System.arraycopy(args, 0, cmdArr, 1, args.length);
} else {
cmdArr = new String[] { command };
}
ProcessBuilder pb = new ProcessBuilder(cmdArr);
File workingDir = (workdir==null ? new File(command).getParentFile() : new File(workdir) );
pb.directory(workingDir);
Process process = pb.start();
// Consume streams, older jvm's had a memory leak if streams were not read,
// some other jvm+OS combinations may block unless streams are consumed.
errorGobbler = new StreamGobbler(process.getErrorStream(), readError);
outputGobbler = new StreamGobbler(process.getInputStream(), readOutput);
errorGobbler.start();
outputGobbler.start();
exitCode = 0;
if (wait) {
try {
process.waitFor();
exitCode = process.exitValue();
} catch (InterruptedException ex) { }
}
return exitCode;
}
public int getExitCode() {
return exitCode;
}
public boolean isOutputCompleted() {
return (outputGobbler != null ? outputGobbler.isCompleted() : false);
}
public boolean isErrorCompleted() {
return (errorGobbler != null ? errorGobbler.isCompleted() : false);
}
public String getOutput() {
return (outputGobbler != null ? outputGobbler.getOutput() : null);
}
public String getError() {
return (errorGobbler != null ? errorGobbler.getOutput() : null);
}
//********************************************
//********************************************
/**
* StreamGobbler reads inputstream to "gobble" it.
* This is used by Executor class when running
* a commandline applications. Gobblers must read/purge
* INSTR and ERRSTR process streams.
* http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=4
*/
private class StreamGobbler extends Thread {
private InputStream is;
private StringBuilder output;
private volatile boolean completed; // mark volatile to guarantee a thread safety
public StreamGobbler(InputStream is, boolean readStream) {
this.is = is;
this.output = (readStream ? new StringBuilder(256) : null);
}
public void run() {
completed = false;
try {
String NL = System.getProperty("line.separator", "\r\n");
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ( (line = br.readLine()) != null) {
if (output != null)
output.append(line + NL);
}
} catch (IOException ex) {
// ex.printStackTrace();
}
completed = true;
}
/**
* Get inputstream buffer or null if stream
* was not consumed.
* @return
*/
public String getOutput() {
return (output != null ? output.toString() : null);
}
/**
* Is input stream completed.
* @return
*/
public boolean isCompleted() {
return completed;
}
}
}
Here is an example reading output from .vbs script but similar works for linux sh scripts.
ShellExec exec = new ShellExec(true, false);
exec.execute("cscript.exe", null, true,
"//Nologo",
"//B", // batch mode, no prompts
"//T:320", // timeout seconds
"c:/my/script/test1.vbs", // unix path delim works for script.exe
"script arg 1",
"script arg 2",
);
System.out.println(exec.getOutput());
Runtime.exec() returns a Process object, from which you can extract the output of whatever command you ran.
VerboseProcess
utility class from jcabi-log can help you:
String output = new VerboseProcess(
new ProcessBuilder("executable with output")
).stdout();
The only dependency you need:
<dependency>
<groupId>com.jcabi</groupId>
<artifactId>jcabi-log</artifactId>
<version>0.7.5</version>
</dependency>
Using Runtime.exec gives you a process. You can these use getInputStream to get the stdout of this process, and put this input stream into a String, through a StringBuffer for example.
ReferenceURL : https://stackoverflow.com/questions/882772/capturing-stdout-when-calling-runtime-exec
'programing' 카테고리의 다른 글
왜 True / False가 파이썬에서 대문자로 쓰이나요? (0) | 2021.01.15 |
---|---|
크기 조정 후 확장기를 사용하여 WPF 창 크기를 콘텐츠에 맞게 유지하는 방법 (0) | 2021.01.15 |
파이썬에서 HTML 구문 분석-lxml 또는 BeautifulSoup? (0) | 2021.01.15 |
뮤텍스는 변경 가능해야합니까? (0) | 2021.01.15 |
Go 구조체에서 멤버를 초기화하는 방법 (0) | 2021.01.15 |