Groovy thực thi các lệnh shell


178

Groovy thêm executephương thức để Stringthực hiện shell thực hiện khá dễ dàng;

println "ls".execute().text

nhưng nếu xảy ra lỗi, thì không có kết quả đầu ra. Có cách nào dễ dàng để loại bỏ cả lỗi tiêu chuẩn và tiêu chuẩn không? (ngoài việc tạo ra một loạt mã để; tạo hai luồng để đọc cả hai luồng đầu vào, sau đó sử dụng luồng cha để chờ chúng hoàn thành sau đó chuyển đổi chuỗi trở lại văn bản?)

Nó sẽ là tốt đẹp để có một cái gì đó như;

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

Đây link là hữu ích. Chỉ ra cách chạy lệnh shell với bản demo cURL.
Aniket Thakur

Câu trả lời:


207

Ok, tự mình giải quyết nó;

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

hiển thị:

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


13
Trong trường hợp bạn cũng cần đặt Biến môi trường cho quy trình này, hãy đảm bảo bọc lệnh trong shell. Ví dụ: chạy lệnh Perforce với 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 không liên quan đến câu hỏi OP, nhưng tôi nghĩ rằng các JVM hiện đại xử lý đồng bộ hóa không mong muốn chỉ là tốt. Vì vậy, StringBuffer không có khả năng làm giảm hiệu suất trong các kịch bản giới hạn luồng hoặc ngăn xếp.
Pavel Grushetzky

3
Các tài liệu nói rằng chúng ta nên sử dụng WaitForProcessOutput () - "Để đợi đầu ra được tiêu thụ hoàn toàn, hãy gọi WaitForProcessOutput ()". Nguồn: docs.groovy-lang.org/latest/html/groovy-jdk/java/lang/ trộm
Srikanth

4
@srikanth các tài liệu đầu ra WaitForProcess () cũng nói "Sử dụng phương pháp này nếu bạn không quan tâm đến đầu ra tiêu chuẩn hoặc lỗi và chỉ muốn quá trình chạy âm thầm" - Tôi muốn đầu ra
Bob Herrmann

sout và serr có thể không có sẵn ngay cả sau khi WaitForOrKill. Đã thử nghiệm bằng cách sử dụng một xác nhận thay vì println. Tài liệu nói: "Đối với điều này, hai Chủ đề được bắt đầu, vì vậy phương thức này sẽ trả về ngay lập tức. Các chủ đề sẽ không được nối () ed, ngay cả khi WaitFor () được gọi . Để chờ đầu ra được tiêu thụ hoàn toàn, hãy gọi WaitForProcessOutput () . "
solstice333

49

"ls".execute()trả về một Processđối tượng đó là lý do tại sao "ls".execute().texthoạt động. Bạn có thể chỉ cần đọc luồng lỗi để xác định xem có lỗi nào không.

Có một phương thức bổ sung Processcho phép bạn vượt qua a StringBufferđể lấy văn bản : consumeProcessErrorStream(StringBuffer error).

Thí dụ:

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

println proc.text
println b.toString()

Nó không hoạt động với tập lệnh Morr Again Shell! # / Bin / bash,
Rashmi Jain

1
Nếu làm việc với các tập lệnh bash, bạn có thể gọi bash như một phần của lệnh: "/ 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 Điều này cho thấy đầu ra tăng dần khi đầu ra được tạo ra .. điều này cực kỳ quan trọng đối với một quá trình chạy dài
samarjit samanta

chia sẻ tuyệt vời ở đó @ mholm815
Jimmy Obonyo Abor

2
Để sử dụng giải pháp này, hãy đưa ra dòng sau:runCommand("echo HELLO WORLD")
Miron V

@ mholm815 làm thế nào chúng ta có thể phê duyệt các tập lệnh được yêu cầu từ chính đường ống?
Ronak Patel

25

Tôi thấy điều này thành ngữ hơn:

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"

Như một bài đăng khác đề cập, đây là những cuộc gọi chặn, nhưng vì chúng tôi muốn làm việc với đầu ra, điều này có thể cần thiết.


24

Để thêm một thông tin quan trọng vào câu trả lời được cung cấp ở trên -

Cho một quá trình

def proc = command.execute();

luôn cố gắng sử dụng

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

thay vì

def output = proc.in.text;

để nắm bắt các kết quả đầu ra sau khi thực hiện các lệnh trong Groovy vì sau này là một cuộc gọi chặn ( câu hỏi SO vì lý do ).


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
Tôi thực sự khó chịu khi một người dành thời gian để đưa ra câu trả lời và ai đó chỉ đánh giá thấp nó mà không có lý do rõ ràng. nếu đây là một cộng đồng, người ta nên cảm thấy bắt buộc phải thêm một bình luận (trừ khi đó là một lý do rất rõ ràng mà bất kỳ lập trình viên có thẩm quyền nào sẽ thấy ngay lập tức) giải thích về downvote.
Amos Bordowitz

5
@AmosBordowitz Rất nhiều câu trả lời nhận được downvote. Không sao, đó là một downvote. Điều đó nói rằng, đó có thể là do mã không có lời giải thích - không phải lúc nào cũng được đón nhận.
Chris Baker

@ChrisBaker vậy tại sao không chỉ ra? Bản thân bạn không tích cực rằng đây là lý do ..
Amos Bordowitz

4
@AmosBordowitz Tôi không phải là người giải thích chính thức, tôi không thể nói cho bạn biết tại sao không, và tôi không chắc chắn vì chúng tôi đang nói về một hành động được thực hiện bởi một cá nhân khác. Tôi đưa ra một khả năng. Tại sao không giải thích downvote, chắc chắn, tại sao không giải thích mã trong câu trả lời? Bằng mọi giá, tôi chắc chắn tất cả chúng ta sẽ ổn thôi.
Chris Baker

1
@ChrisBakerI chưa bao giờ đưa ra bất kỳ khiếu nại nào như vậy ("nhưng tôi đoán bạn biết rõ hơn"). Đó là một điều
khôn ngoan

-3
command = "ls *"

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

nhưng nếu lệnh thất bại, quá trình sẽ chấm dứt


Nơi nào shđến từ đâu?
styl3r

3
shlà một phần của DSL Groovy Jenkins. Có lẽ không hữu ích ở đây
Gi0rgi0s

4
Jenkins Groovy DSL! = Groovy
Skeeve 23/11/18

như những người khác đã tuyên bố, đây là một phần của Jenkins DSL
jonypony3

Câu trả lời này không áp dụng cho câu hỏi đã được hỏi.
Brandon
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.