쉘 명령을 실행하는 Groovy


178

Groovy는 쉘 실행을 상당히 쉽게 만드는 execute방법을 추가합니다 String.

println "ls".execute().text

그러나 오류가 발생하면 결과 출력이 없습니다. 표준 오류와 표준을 모두 쉽게 얻을 수있는 방법이 있습니까? (다발의 코드를 만드는 것; 두 개의 스레드를 만들어 두 입력 스트림을 모두 읽은 다음 부모 스트림을 사용하여 완료 될 때까지 기다렸다가 문자열을 다시 텍스트로 변환 하시겠습니까?)

다음과 같은 것이 좋습니다.

 def x = shellDo("ls /tmp/NoFile")
 println "out: ${x.out} err:${x.err}"

링크 는 유용합니다. cURL 데모로 쉘 명령을 실행하는 방법을 보여줍니다.
Aniket Thakur

답변:


207

좋아, 스스로 해결했다.

def sout = new StringBuilder(), serr = new StringBuilder()
def proc = 'ls /badDir'.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println "out> $sout err> $serr"

표시합니다 :

out> err> ls: cannot access /badDir: No such file or directory


13
환경 변수 도이 프로세스 로 설정해야하는 경우 명령을 쉘로 랩핑해야합니다. 예를 들어, env vars를 사용하여 Perforce 명령 실행 :envVars = ["P4PORT=p4server:2222", "P4USER=user", "P4PASSWD=pass", "P4CLIENT=p4workspace"]; workDir = new File("path"); cmd = "bash -c \"p4 change -o 1234\""; proc = cmd.execute(envVars, workDir);
Noam Manos

@paul_sns는 OP 질문과 관련이 없지만 현대 JVM은 비경쟁 동기화를 잘 처리한다고 생각합니다. 따라서 StringBuffer는 스레드 또는 스택 제한 시나리오에서 성능을 저하시키지 않을 것입니다.
Pavel Grushetzky 2016 년

3
문서에 따르면 waitForProcessOutput ()- "출력이 완전히 소비 될 때까지 기다리려면 waitForProcessOutput ()을 호출해야합니다."라고 말합니다. 출처 : docs.groovy-lang.org/latest/html/groovy-jdk/java/lang/…
Srikanth

4
@srikanth "당신이 표준 또는 오류 출력 관심 단지 프로세스가 자동으로 실행하지 않으려면이 방법을 사용하여"를 waitForProcess () 출력 문서는 말을 - I 출력을 원하는
밥 헤르만

waitForOrKill 이후에도 sout 및 serr을 사용하지 못할 수 있습니다. println 대신 assert를 사용하여 테스트했습니다. 문서에 따르면 : "2 개의 스레드가 시작되므로이 메소드는 즉시 리턴됩니다. waitFor ()가 호출 되더라도 스레드는 join ()되지 않습니다 . 출력이 완전히 소비 될 때까지 기다리려면 waitForProcessOutput ()을 호출하십시오. "
solstice333

49

"ls".execute()작동 하는 Process객체를 반환 "ls".execute().text합니다. 오류 스트림을 읽고 오류가 있는지 판별 할 수 있어야합니다.

텍스트를 검색하기 위해 Processa StringBuffer를 전달할 수 있는 추가 방법이 있습니다 consumeProcessErrorStream(StringBuffer error)..

예:

def proc = "ls".execute()
def b = new StringBuffer()
proc.consumeProcessErrorStream(b)

println proc.text
println b.toString()

Bourn Again Shell 스크립트에서는 작동하지 않습니다! # / bin / bash,
Rashmi Jain

1
bash 스크립트로 작업하는 경우 "/ bin / bash script".execute () 명령의 일부로 bash를 호출 할 수 있습니다.
Niels Bech Nielsen

32
// a wrapper closure around executing a string                                  
// can take either a string or a list of strings (for arguments with spaces)    
// prints all output, complains and halts on error                              
def runCommand = { strList ->
  assert ( strList instanceof String ||
           ( strList instanceof List && strList.each{ it instanceof String } ) \
)
  def proc = strList.execute()
  proc.in.eachLine { line -> println line }
  proc.out.close()
  proc.waitFor()

  print "[INFO] ( "
  if(strList instanceof List) {
    strList.each { print "${it} " }
  } else {
    print strList
  }
  println " )"

  if (proc.exitValue()) {
    println "gave the following error: "
    println "[ERROR] ${proc.getErrorStream()}"
  }
  assert !proc.exitValue()
}

10
+1 출력이 생성됨에 따라 출력을 증분으로 표시합니다. 이는 장기 실행 프로세스에 매우 중요합니다.
samarjit samanta

@ mholm815
Jimmy Obonyo Abor가

2
이 솔루션을 사용하려면 다음 줄을 발행하십시오.runCommand("echo HELLO WORLD")
Miron V

@ mholm815 파이프 라인 자체에서 필요한 스크립트를 어떻게 승인 할 수 있습니까?
Ronak Patel

25

나는 이것을 더 관용적이라고 생각한다.

def proc = "ls foo.txt doesnotexist.txt".execute()
assert proc.in.text == "foo.txt\n"
assert proc.err.text == "ls: doesnotexist.txt: No such file or directory\n"

다른 게시물에서 언급했듯이, 이들은 호출을 차단하지만 출력 작업을 원하므로 이것이 필요할 수 있습니다.


24

위에 제공된 답변에 하나 이상의 중요한 정보를 추가하려면-

프로세스

def proc = command.execute();

항상 사용하려고

def outputStream = new StringBuffer();
proc.waitForProcessOutput(outputStream, System.err)
//proc.waitForProcessOutput(System.out, System.err)

오히려

def output = proc.in.text;

후자는 블로킹 호출이기 때문에 groovy에서 명령을 실행 한 후 출력을 캡처합니다 ( 이유는 SO 질문 ).


6
def exec = { encoding, execPath, execStr, execCommands ->

def outputCatcher = new ByteArrayOutputStream()
def errorCatcher = new ByteArrayOutputStream()

def proc = execStr.execute(null, new File(execPath))
def inputCatcher = proc.outputStream

execCommands.each { cm ->
    inputCatcher.write(cm.getBytes(encoding))
    inputCatcher.flush()
}

proc.consumeProcessOutput(outputCatcher, errorCatcher)
proc.waitFor()

return [new String(outputCatcher.toByteArray(), encoding), new String(errorCatcher.toByteArray(), encoding)]

}

def out = exec("cp866", "C:\\Test", "cmd", ["cd..\n", "dir\n", "exit\n"])

println "OUT:\n" + out[0]
println "ERR:\n" + out[1]

3
나는 사람이 시간을내어 답변을했고 누군가가 명백한 이유없이 그것을 내려 놓았다는 것이 정말로 화가납니다. 이것이 커뮤니티 인 경우, 공감대를 설명하는 (유능한 프로그래머가 즉시 볼 수있는 명백한 이유가 아닌 한) 의견을 추가해야 할 의무가 있습니다.
Amos Bordowitz

6
@AmosBordowitz 많은 답변이 다운 보트를받습니다. 괜찮아요, 하나의 downvote입니다. 즉, 설명이없는 코드이기 때문에 항상 수신되는 것은 아닙니다.
Chris Baker

@ChrisBaker 그래서 왜 지적하지? 당신 자신은 ..이는 이유는 긍정적 없습니다
아모스 Bordowitz

5
@AmosBordowitz 저는 공식 공무원 설명자가 아니며 그 이유를 말할 수 없으며 다른 개인이 취한 조치에 대해 이야기하고 있기 때문에 확실하지 않다는 것을 이해할 수 있습니다. 나는 하나의 가능성을 제안했다. 왜 downvote를 설명하지 않습니까? 왜 대답에 코드를 설명하지 않습니까? 어쨌든, 나는 우리 모두 괜찮을 것이라고 확신합니다.
Chris Baker

1
@ChrisBaker 나는 그런 주장을 한 적이 없다. 지식이 아닌 품위있는 일입니다.
Amos Bordowitz

-3
command = "ls *"

def execute_state=sh(returnStdout: true, script: command)

그러나 명령이 실패하면 프로세스가 종료됩니다.


어디 sh에서 왔습니까?
styl3r

3
shJenkins 그루비 DSL의 일부입니다. 아마 여기서 유용하지 않음
Gi0rgi0s

4
Jenkins Groovy DSL! = Groovy
Skeeve

다른 사람들이 말했듯이, 이것은 Jenkins DSL의 일부입니다
jonypony3

이 답변은 질문과 대답에 해당되지 않습니다.
Brandon
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.