Jenkinsfile'den (groovy) bir değişkene kullanarak yürütülen bir shell komutunun çıktısını nasıl alabilirim?


213

Jenkinsfile (Groovy) böyle bir şey var ve daha sonra bilgileri kullanmak için bir değişken stdout ve çıkış kodu kaydetmek istiyorum.

sh "ls -l"

Bunu nasıl yapabilirim, özellikle de içinde herhangi bir harika kod çalıştıramayacağınız gibi Jenkinsfile?



Yanıtlar:


391

Boru hattı shadımının en son sürümü aşağıdakileri yapmanızı sağlar;

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

Başka bir özellik de returnStatusseçenektir.

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

Dayalı eklendi Bu seçenekler bu konuda.

Komut için resmi belgelere bakın sh.



Gerçi benim için "vars" öneki ile çalışmıyor. Ben sadece önek olmadan var adı olarak GIT_COMMIT_EMAIL kullandığımda her şey yolunda.
Bastian Voigt


7
Bildirici jenkinsfile sözdizimi kullandığımda, bu işe yaramaz, hata iletisi:WorkflowScript: 97: Expected a step @ line 97, column 17.
İngiliz anahtarı

17
Bu sadece bir scriptadım bloğu içinde çalışıyor gibi görünüyor . jenkins.io/doc/book/pipeline/syntax/#declarative-steps
pirinç maymunu

51

Mevcut Boru Hattı sürümü yerel olarak destekler returnStdoutve / adımlardan returnStatusçıktı veya durum almayı mümkün kılar .shbat

Bir örnek:

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

Resmi bir belge .


Birisi stackoverflow.com/questions/40946697/… için bana yardımcı olabilir mi? Şimdiden teşekkürler!
Jitesh Sojitra

3
İfadeler bir script { }adımda sarılacaktır .
x-yuri

40

hızlı cevap şudur:

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

Bence sh adımının sonucunu alabilmek için bir özellik isteği var, ama bildiğim kadarıyla şu anda başka bir seçenek yok.

DÜZENLEME: JENKINS-26133

EDIT2: Hangi sürümden beri tam olarak emin değilim, ancak sh / bat adımları artık std çıktısını döndürebilir, basitçe:

def output = sh returnStdout: true, script: 'ls -l'

1
Ayrıca FYI, yarasa adımları çalıştırılan komutu yansıtır, bu nedenle sadece çıktı almak için yarasa komutlarını @ ile başlatmanız gerekir (örn. "@Dir").
Russell Gallop

21

Stdout'u almak ve komutun başarılı olup olmadığını bilmek istiyorsanız, returnStdoutbunu bir istisna işleyicisine kullanın ve sarın:

kodlanmış boru hattı

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

çıktı :

[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

Ne yazık ki hudson.AbortException bu çıkış durumunu elde etmek için herhangi bir yararlı yöntemi içermiyor, bu nedenle gerçek değer gerekiyorsa iletiden ayrıştırmanız gerekir (ugh!)

Javadoc'un aksine https://javadoc.jenkins-ci.org/hudson/AbortException.html Bu kural dışı durum yakalandığında derleme başarısız olmaz . O ne zaman başarısız değil yakalandı!

Güncelleme: STDERR çıktısının shell komutundan da olmasını istiyorsanız, Jenkins maalesef bu yaygın kullanım durumunu düzgün bir şekilde destekleyemiyor. Bir JENKINS-44930 2017 bileti , bir çözüme doğru ilerleme kaydederken, bir ping-pong durumunda sıkıştı - lütfen oyunuzu eklemeyi düşünün.

Şimdi bir çözüme gelince , birkaç olası yaklaşım olabilir:

a) STDERR'ı STDOUT'a yönlendirin 2>&1 - ancak bunu ana çıkıştan ayrıştırmak size kalmıştır ve komut başarısız olursa çıktıyı alamazsınız - çünkü istisna işleyicisindesiniz.

b) STDERR'ı geçici bir dosyaya (daha önce hazırladığınız adı) yönlendirin 2>filename(ancak daha sonra dosyayı temizlemeyi unutmayın) - yani. ana kod:

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) Diğer yöne gidin, returnStatus=truebunun yerine ayarlayın , istisna işleyicisinden vazgeçin ve çıktıyı her zaman bir dosyaya kaydedin, yani:

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
}

Dikkat: yukarıdaki kod Unix / Linux'a özgüdür - Windows tamamen farklı kabuk komutları gerektirir.


1
"ls: dir1 erişemezsiniz: böyle bir dosya veya dizin yok" ve sadece "hudson.AbortException: komut dosyası çıkış kodu 2 döndü" olarak almak için bir şans var mı?
user2988257

Bunun nasıl çalışabileceğini görmüyorum. Testlerimde çıktı metni asla atanmaz ve bu beklenen bir durumdur. Kabuk adımından atılan istisna, dönüş değerinin atanmasını önler
Jakub Bochenski

2
returnStatus ve returnStdout maalesef aynı anda çalışmıyor. İşte bilet. Lütfen oy verin: issue.jenkins-ci.org/browse/JENKINS-44930 .
Alexander Samoylov

1
@AlexanderSamoylov Yukarıdaki seçenek (c) 'de olduğu gibi bir dosyayı kullanarak geçici çözüm bulmak zorundasınız. Ne yazık ki bu araçların yazarları sık sık tartışılıyor ve diğer yaygın kullanım durumları için ileriyi düşünmüyorlar.
Ed Randall

1
@Ed Randall, Sana tamamen katılıyorum .. Bu yüzden bu sayıyı daha fazla oy nedeniyle bir şeyler yapmaya başladıklarını umarak yayınladım.
Alexander Samoylov

12

bu örnek bir durum, inanıyorum mantıklı olacak!

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


    echo "${commit[-1]} "

    }
}

Yolu bilmiyorum ama cevabınız bana çok yardımcı oluyor, teşekkür ederim :)
shaharnakash

5

Çıkışı groovy yerine sonraki kabuk komutlarında kullanması gerekenler için bu örnek gibi bir şey yapılabilir:

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

Kod maven örnekleri oldukça yararlı buldum .


-6

En kolay yol bu şekilde kullanmaktır

my_var=`echo 2` echo $my_var çıktı: 2

basit olmadığını unutmayın tek alıntı geri alıntı (`).


Seçilmiş, ancak bunların shaksi takdirde insanların mükemmel olduğunu düşünebileceklerini, özellikle de bas komut dosyalarına aşina olmadıklarını göstermenizi öneririm . Sadece ls -lyerine Jenkins üzerinde denedim echo 2ve işe yarıyor. Aslında bu yaklaşımı daha önce kullanmıştım, ama bir alternatif arıyordum çünkü çok güvenilir değil. Bu şekilde standart bir kabuk üzerinde yakalanan daha karmaşık bir komutun çıktısı var, ancak Jenkins'e taşındığında sh, bilinmeyen bir nedenden dolayı değişken hiçbir şey tutmuyor.
Nagev
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.