Groovy menjalankan perintah shell

178

Groovy menambahkan executemetode Stringuntuk membuat mengeksekusi shell cukup mudah;

println "ls".execute().text

tetapi jika kesalahan terjadi, maka tidak ada output yang dihasilkan. Apakah ada cara mudah untuk mengeluarkan standard error dan standard out? (selain membuat banyak kode untuk; membuat dua utas untuk membaca kedua aliran input, kemudian menggunakan aliran induk untuk menunggu mereka selesai kemudian mengonversi string kembali ke teks?)

Akan menyenangkan memiliki sesuatu seperti;

 def x = shellDo("ls /tmp/NoFile")
 println "out: ${x.out} err:${x.err}"
Bob Herrmann
sumber
Ini link yang berguna. Memperlihatkan cara menjalankan perintah shell dengan cURL demo.
Aniket Thakur

Jawaban:

207

Oke, selesaikan sendiri;

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

menampilkan:

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

Bob Herrmann
sumber
13
Jika Anda juga perlu mengatur Variabel Lingkungan ke proses ini, pastikan untuk membungkus perintah di shell. Misalnya, menjalankan perintah Perforce dengan 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 tidak terkait dengan pertanyaan OP, tapi saya pikir JVM modern menangani sinkronisasi yang tidak dikontrol dengan baik. Jadi StringBuffer tidak mungkin menurunkan kinerja dalam skenario thread-atau stack-terbatas.
Pavel Grushetzky
3
Dokumen mengatakan bahwa kita harus menggunakan waitForProcessOutput () - "Untuk menunggu output dikonsumsi sepenuhnya panggil waitForProcessOutput ()". Sumber: docs.groovy-lang.org/latest/html/groovy-jdk/java/lang/…
Srikanth
4
@srikanth the waitForProcess () output docs juga mengatakan "Gunakan metode ini jika Anda tidak peduli dengan output standar atau kesalahan dan hanya ingin proses berjalan diam-diam" - Saya ingin hasilnya
Bob Herrmann
sout dan serr mungkin tidak tersedia bahkan setelah waitForOrKill. Diuji menggunakan pernyataan alih-alih println. Documents mengatakan: "Untuk ini, dua utas dimulai, jadi metode ini akan segera kembali. Utas tidak akan bergabung () ed, bahkan jika waitFor () dipanggil . Untuk menunggu output dikonsumsi sepenuhnya panggil waitForProcessOutput () . "
solstice333
49

"ls".execute()mengembalikan Processobjek yang mengapa "ls".execute().textbekerja. Anda harus bisa membaca aliran kesalahan untuk menentukan apakah ada kesalahan.

Ada metode ekstra pada Processyang memungkinkan Anda untuk melewati StringBufferuntuk mengambil teks: consumeProcessErrorStream(StringBuffer error).

Contoh:

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

println proc.text
println b.toString()
Joshua
sumber
Ini tidak bekerja dengan skrip Bourn Again Shell! # / Bin / bash,
Rashmi Jain
1
Jika bekerja dengan skrip bash, Anda mungkin memanggil bash sebagai bagian dari perintah: "/ 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()
}
mholm815
sumber
10
+1 Ini menunjukkan output secara bertahap saat output dihasilkan..yang sangat penting untuk proses yang berjalan lama
samarjit samanta
share hebat di sana @ mholm815
Jimmy Obonyo Abor
2
Untuk menggunakan solusi ini, terbitkan baris berikut:runCommand("echo HELLO WORLD")
Miron V
@ mholm815 bagaimana kita bisa menyetujui skrip yang diperlukan dari pipa itu sendiri?
Ronak Patel
25

Saya menemukan ini lebih idiomatis:

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"

Seperti posting lain menyebutkan, ini memblokir panggilan, tetapi karena kami ingin bekerja dengan output, ini mungkin diperlukan.

solstice333
sumber
24

Untuk menambahkan satu lagi informasi penting ke jawaban yang diberikan di atas -

Untuk suatu proses

def proc = command.execute();

selalu coba gunakan

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

daripada

def output = proc.in.text;

untuk menangkap output setelah menjalankan perintah di groovy karena yang terakhir adalah panggilan pemblokiran ( SO pertanyaan karena alasan ).

Aniket Thakur
sumber
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]
emles-kz
sumber
3
Saya benar-benar kesal karena seseorang meluangkan waktu untuk memberikan jawaban dan seseorang hanya menurunkannya tanpa alasan yang jelas. jika ini adalah sebuah komunitas, seseorang harus merasa berkewajiban untuk menambahkan komentar (kecuali itu adalah alasan yang sangat jelas bahwa setiap programmer yang kompeten akan segera melihat) menjelaskan downvote.
Amos Bordowitz
5
@AmosBordowitz Banyak jawaban mendapatkan downvotes. Tidak apa-apa, ini satu downvote. Yang mengatakan, itu bisa jadi karena itu kode tanpa kata penjelasan - tidak selalu diterima dengan baik.
Chris Baker
@ ChrisBaker jadi mengapa tidak menunjukkannya? Anda sendiri tidak yakin bahwa inilah alasannya ..
Amos Bordowitz
4
@AmosBordowitz Saya bukan penjelajah undian resmi, saya tidak bisa memberi tahu Anda mengapa tidak, dan bisa dimengerti bahwa saya tidak yakin karena kita sedang berbicara tentang tindakan yang diambil oleh orang lain. Saya menawarkan satu kemungkinan. Mengapa tidak menjelaskan downvote, tentu, mengapa tidak menjelaskan kode dalam jawabannya? Bagaimanapun, saya yakin kita semua akan baik-baik saja.
Chris Baker
1
@ChrisBakerI tidak pernah membuat klaim seperti itu ("tapi saya rasa Anda lebih tahu"). Itu hal kesopanan, bukan hal pengetahuan ..
Amos Bordowitz
-3
command = "ls *"

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

tetapi jika perintah gagal proses akan berakhir

舒何伟
sumber
Dari mana datangnya sh?
styl3r
3
shadalah bagian dari DSL Jenkins asyik. Mungkin tidak berguna di sini
Gi0rgi0s
4
Jenkins Groovy DSL! = Groovy
Skeeve
seperti yang orang lain katakan, ini adalah bagian dari Jenkins DSL
jonypony3
Jawaban ini tidak berlaku untuk pertanyaan yang diajukan.
Brandon