Bagaimana cara saya mendapatkan output dari perintah shell yang dieksekusi menggunakan variabel dari Jenkinsfile (groovy)?

213

Saya memiliki sesuatu seperti ini di Jenkinsfile (Groovy) dan saya ingin merekam stdout dan kode keluar dalam sebuah variabel untuk menggunakan informasi nanti.

sh "ls -l"

Bagaimana saya bisa melakukan ini, terutama karena tampaknya Anda tidak dapat benar-benar menjalankan segala jenis kode asyik di dalam Jenkinsfile?

Sorin
sumber

Jawaban:

393

Versi terbaru dari shlangkah pipeline memungkinkan Anda untuk melakukan hal berikut;

// Git committer email
GIT_COMMIT_EMAIL = sh (
    script: 'git --no-pager show -s --format=\'%ae\'',
    returnStdout: true
).trim()
echo "Git committer email: ${GIT_COMMIT_EMAIL}"

Fitur lainnya adalah returnStatusopsi.

// Test commit message for flags
BUILD_FULL = sh (
    script: "git log -1 --pretty=%B | grep '\\[jenkins-full]'",
    returnStatus: true
) == 0
echo "Build full flag: ${BUILD_FULL}"

Opsi-opsi ini ditambahkan berdasarkan masalah ini .

Lihat dokumentasi resmi untuk shperintah tersebut.

G. Roggemans
sumber
11
Sepertinya sekarang sudah didokumentasikan -> jenkins.io/doc/pipeline/steps/workflow-durable-task-step/…
zot24
Tidak bekerja untuk saya dengan awalan "vars". Ketika saya hanya menggunakan GIT_COMMIT_EMAIL sebagai nama var tanpa awalan semua baik-baik saja.
Bastian Voigt
Tolong bantu saya untuk stackoverflow.com/questions/40946697/…
Jitesh Sojitra
7
Ketika saya menggunakan sintaks jenkinsfile deklaratif, ini tidak berfungsi, pesan kesalahan adalah:WorkflowScript: 97: Expected a step @ line 97, column 17.
Wrench
17
Tampaknya ini hanya berfungsi di dalam scriptblok langkah. jenkins.io/doc/book/pipeline/syntax/#declarative-steps
brass monkey
51

Versi Pipeline saat ini secara native mendukung returnStdoutdan returnStatus, yang memungkinkan untuk mendapatkan output atau status dari sh/ batlangkah-langkah.

Sebuah contoh:

def ret = sh(script: 'uname', returnStdout: true)
println ret

Dokumentasi resmi .

luka5z
sumber
Dapatkah seseorang membantu saya untuk stackoverflow.com/questions/40946697/… ? Terima kasih sebelumnya!
Jitesh Sojitra
3
Pernyataan harus dibungkus dalam script { }langkah.
x-yuri
40

jawaban cepatnya adalah ini:

sh "ls -l > commandResult"
result = readFile('commandResult').trim()

Saya pikir ada permintaan fitur untuk bisa mendapatkan hasil dari langkah sh, tetapi sejauh yang saya tahu, saat ini tidak ada pilihan lain.

EDIT: JENKINS-26133

EDIT2: Tidak yakin sejak versi apa, tetapi langkah sh / bat sekarang dapat mengembalikan output std, cukup:

def output = sh returnStdout: true, script: 'ls -l'
Radianovmar
sumber
1
Juga FYI, langkah-langkah bat echo perintah sedang dijalankan sehingga Anda perlu memulai perintah kelelawar dengan @ untuk hanya mendapatkan output (misalnya "@dir").
Russell Gallop
21

Jika Anda ingin mendapatkan stdout DAN tahu apakah perintahnya berhasil atau tidak, gunakan saja returnStdout dan bungkuslah dengan penangan pengecualian:

pipa scripted

try {
    // Fails with non-zero exit if dir1 does not exist
    def dir1 = sh(script:'ls -la dir1', returnStdout:true).trim()
} catch (Exception ex) {
    println("Unable to read dir1: ${ex}")
}

keluaran :

[Pipeline] sh
[Test-Pipeline] Running shell script
+ ls -la dir1
ls: cannot access dir1: No such file or directory
[Pipeline] echo
unable to read dir1: hudson.AbortException: script returned exit code 2

Sayangnya hudson.AbortException tidak memiliki metode yang berguna untuk mendapatkan status keluar itu, jadi jika nilai aktual diperlukan Anda harus menguraikannya keluar dari pesan (ugh!)

Bertentangan dengan Javadoc https://javadoc.jenkins-ci.org/hudson/AbortException.html build tersebut adalah tidak gagal ketika pengecualian ini ditangkap. Gagal saat tidak tertangkap!

Memperbarui: Jika Anda juga ingin keluaran STDERR dari perintah shell, Jenkins sayangnya gagal untuk mendukung kasus penggunaan umum dengan benar. Tiket 2017 JENKINS-44930 macet dalam kondisi ping-pong yang beralasan sementara tidak membuat kemajuan menuju solusi - harap pertimbangkan untuk menambahkan suara Anda ke dalamnya.

Sebagai solusi sekarang , mungkin ada beberapa pendekatan yang mungkin:

a) Redirect STDERR ke STDOUT 2>&1 - tetapi terserah Anda untuk menguraikannya dari output utama, dan Anda tidak akan mendapatkan output jika perintah gagal - karena Anda berada di handler pengecualian.

b) redirect STDERR ke file sementara (nama yang Anda persiapkan sebelumnya) 2>filename(tapi ingat untuk membersihkan file sesudahnya) - yaitu. kode utama menjadi:

def stderrfile = 'stderr.out'
try {
    def dir1 = sh(script:"ls -la dir1 2>${stderrfile}", returnStdout:true).trim()
} catch (Exception ex) {
    def errmsg = readFile(stderrfile)
    println("Unable to read dir1: ${ex} - ${errmsg}")
}

c) Pergi ke arah lain, atur returnStatus=truesebagai gantinya, membuang pengecualian handler dan selalu menangkap output ke file, yaitu:

def outfile = 'stdout.out'
def status = sh(script:"ls -la dir1 >${outfile} 2>&1", returnStatus:true)
def output = readFile(outfile).trim()
if (status == 0) {
    // output is directory listing from stdout
} else {
    // output is error message from stderr
}

Peringatan: kode di atas adalah khusus Unix / Linux - Windows memerlukan perintah shell yang sama sekali berbeda.

Ed Randall
sumber
1
apakah ada peluang untuk mendapatkan output sebagai "ls: tidak dapat mengakses dir1: Tidak ada file atau direktori" dan bukan hanya "hudson.AbortException: skrip mengembalikan kode keluar 2"?
user2988257
Saya tidak melihat bagaimana ini bisa berhasil. Dalam pengujian saya, teks keluaran tidak pernah ditugaskan dan ini yang diharapkan. Pengecualian yang dilemparkan dari langkah shell mencegah nilai pengembalian ditugaskan
Jakub Bochenski
2
Sayangnya, returnStatus dan returnStdout tidak berfungsi pada saat yang bersamaan. Ini tiketnya. Silakan, beri suara: issues.jenkins-ci.org/browse/JENKINS-44930 .
Alexander Samoylov
1
@AlexanderSamoylov Anda harus bekerja menggunakan file seperti pada opsi (c) di atas. Sayangnya penulis alat ini sering berpendapat dan tidak berpikir ke depan untuk kasus penggunaan umum lainnya, 'sh' di sini menjadi contohnya.
Ed Randall
1
@ Ed Randall, Sepenuhnya setuju dengan Anda .. Inilah sebabnya saya memposting masalah ini berharap bahwa karena jumlah suara yang lebih besar mereka mulai melakukan sesuatu.
Alexander Samoylov
12

ini adalah contoh kasus, yang akan masuk akal saya percaya!

node('master'){
    stage('stage1'){
    def commit = sh (returnStdout: true, script: '''echo hi
    echo bye | grep -o "e"
    date
    echo lol''').split()


    echo "${commit[-1]} "

    }
}
Bibek Mantree
sumber
Saya tidak tahu caranya tetapi jawaban Anda sangat membantu saya, terima kasih :)
shaharnakash
5

Bagi mereka yang perlu menggunakan output dalam perintah shell berikutnya, daripada asyik, sesuatu seperti contoh ini bisa dilakukan:

    stage('Show Files') {
        environment {
          MY_FILES = sh(script: 'cd mydir && ls -l', returnStdout: true)
        }
        steps {
          sh '''
            echo "$MY_FILES"
          '''
        }
    }

Saya menemukan contoh pada kode pakar cukup berguna.

Nagev
sumber
-6

Cara termudah adalah menggunakan cara ini

my_var=`echo 2` echo $my_var output: 2

Catatan yang tidak sederhana adalah kutipan tunggal adalah back quote (`).

Ajay Gadhavana
sumber
Terpilih, tetapi saya sarankan Anda menunjukkan bahwa ini harus dibungkus di bawah yang shlain orang mungkin berpikir itu asyik, terutama jika mereka tidak terbiasa dengan bash scripting. Saya baru saja mencobanya di Jenkins, menggunakan ls -lbukan echo 2dan itu berhasil. Saya sebenarnya telah menggunakan pendekatan ini sebelumnya, tetapi telah mencari alternatif karena, itu tidak terlalu dapat diandalkan. Saya memiliki output dari perintah yang lebih kompleks ditangkap pada shell standar dengan cara ini, tetapi ketika porting ke Jenkins shvariabel tidak memiliki apa-apa, untuk beberapa alasan yang tidak diketahui.
Nagev