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?



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.


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


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 .


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'

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.


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]} "

    }
}

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.


-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 (`).


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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.