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
ในกรณีที่คุณต้องตั้งค่าตัวแปรสภาพแวดล้อมให้กับกระบวนการนี้ตรวจสอบให้แน่ใจว่าได้ตัดคำสั่งในเชลล์ ตัวอย่างเช่นการรันคำสั่ง Perforce ด้วย env vars: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

3
เอกสารบอกว่าเราควรใช้ waitForProcessOutput () - "เพื่อรอให้เอาต์พุตหมดสิ้นการเรียกใช้ waitForProcessOutput ()" ที่มา: docs.groovy-lang.org/latest/html/groovy-jdk/java/lang/…
Srikanth

4
@srikanth เอกสารเอาท์พุท waitForProcess () ยังพูดว่า "ใช้วิธีนี้หากคุณไม่สนใจเกี่ยวกับเอาต์พุตมาตรฐานหรือข้อผิดพลาดและเพียงแค่ต้องการให้กระบวนการทำงานอย่างเงียบ ๆ " - ฉันต้องการผลลัพธ์
Bob Herrmann

sout และ serr อาจไม่สามารถใช้ได้แม้หลังจาก waitForOrKill ทดสอบโดยใช้ assert แทน println เอกสารพูดว่า: "สำหรับสิ่งนี้เธรดสองรายการเริ่มต้นดังนั้นวิธีนี้จะส่งคืนทันทีเธรดจะไม่เข้าร่วม () ed แม้ว่าจะมีการเรียกใช้ waitFor ()เพื่อรอให้เอาต์พุตหมดสิ้นการใช้งานการโทรรอฟอเรสต์ ."
solstice333

49

"ls".execute()ส่งคืนProcessวัตถุซึ่งเป็นสาเหตุการ"ls".execute().textทำงาน คุณควรจะสามารถอ่านสตรีมข้อผิดพลาดเพื่อตรวจสอบว่ามีข้อผิดพลาดหรือไม่

มีวิธีการพิเศษในเป็นProcessที่ช่วยให้คุณผ่านการดึงข้อความ:StringBufferconsumeProcessErrorStream(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
หากทำงานกับสคริปต์ทุบตีคุณอาจเรียกใช้งานทุบตีเป็นส่วนหนึ่งของคำสั่ง: "/ bin / bash script" .execute ()
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 เนื่องจากคำสั่งหลังนั้นเป็นการบล็อกการโทร ( ดังนั้นคำถามด้วยเหตุผล )


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
ฉันรำคาญจริง ๆ ที่บุคคลใช้เวลาในการให้คำตอบและบางคน downvoted มันโดยไม่มีเหตุผลชัดเจน ถ้านี่คือชุมชนคุณควรรู้สึกว่าต้องเพิ่มความคิดเห็น (เว้นแต่จะเป็นเหตุผลที่ชัดเจนมากที่โปรแกรมเมอร์ผู้มีความสามารถจะเห็นได้ทันที) อธิบายถึง downvote
Amos Bordowitz

6
@AmosBordowitz คำตอบมากมายรับ downvotes ไม่เป็นไรโหวตได้หนึ่งครั้ง ที่กล่าวว่าอาจเป็นเพราะมันเป็นรหัสที่ไม่มีคำอธิบาย - ไม่ได้รับการตอบรับที่ดีเสมอไป
Chris Baker

@ChrisBaker แล้วทำไมไม่ชี้มันออกมาล่ะ? คุณเองยังไม่แน่ใจว่านี่คือเหตุผล ..
Amos Bordowitz

5
@AmosBordowitz ฉันไม่ใช่นักสำรวจ downvote อย่างเป็นทางการฉันไม่สามารถบอกคุณได้ว่าทำไมไม่และเป็นที่เข้าใจได้ว่าฉันไม่แน่ใจเพราะเรากำลังพูดถึงการกระทำของบุคคลอื่น ฉันเสนอความเป็นไปได้หนึ่งอย่าง ทำไมไม่อธิบาย downvote แน่นอนทำไมไม่อธิบาย code ในคำตอบ? ผมมั่นใจว่าเราจะไม่เป็นไร
Chris Baker

1
@ChrisBakerI ไม่เคยเรียกร้องใด ๆ ("แต่ฉันคิดว่าคุณรู้ดีกว่า") มันเป็นสิ่งที่เหมาะสมไม่ใช่เรื่องที่รู้ ..
Amos Bordowitz

-3
command = "ls *"

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

แต่หากคำสั่งล้มเหลวกระบวนการจะยุติลง


ในกรณีที่ไม่shมาจากไหน?
styl3r

3
shเป็นส่วนหนึ่งของ Jenkins groovy DSL อาจไม่มีประโยชน์ที่นี่
Gi0rgi0s

4
Jenkins Groovy DSL! = Groovy
Skeeve

ดังที่คนอื่นได้กล่าวมานี่เป็นส่วนหนึ่งของ Jenkins DSL
jonypony3

คำตอบนี้ไม่สามารถใช้ได้กับคำถามที่ถาม
แบรนดอน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.