ฉันจะรับเอาต์พุตของคำสั่งเชลล์ที่ดำเนินการโดยใช้เป็นตัวแปรจาก Jenkinsfile (groovy) ได้อย่างไร


213

ฉันมีสิ่งนี้ใน Jenkinsfile (Groovy) และฉันต้องการบันทึก stdout และรหัสทางออกในตัวแปรเพื่อใช้ข้อมูลในภายหลัง

sh "ls -l"

ฉันจะทำสิ่งนี้ได้อย่างไรโดยเฉพาะอย่างยิ่งเนื่องจากดูเหมือนว่าคุณไม่สามารถเรียกใช้โค้ด Groovy ใด ๆ ภายในJenkinsfile?


2
ซ้ำของstackoverflow.com/questions/36507410/...
Jesse Glick

คำตอบ:


391

ไปป์ไลน์เวอร์ชันล่าสุดshช่วยให้คุณสามารถทำสิ่งต่อไปนี้

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

คุณสมบัติอื่นเป็นreturnStatusตัวเลือก

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

ตัวเลือกเหล่านี้ที่เพิ่มขึ้นอยู่กับนี้ปัญหา

ดูเอกสารประกอบอย่างเป็นทางการสำหรับshคำสั่ง


11
ดูเหมือนตอนนี้จะมีการบันทึกไว้ -> jenkins.io/doc/pipeline/steps/workflow-durable-task-step/ ......
zot24

ไม่ทำงานสำหรับฉันด้วยคำนำหน้า "vars" เมื่อฉันใช้ GIT_COMMIT_EMAIL เป็นชื่อ var โดยไม่มีคำนำหน้าทั้งหมดก็ใช้ได้
Bastian Voigt

โปรดช่วยฉันสำหรับstackoverflow.com/questions/40946697/ …
Jitesh Sojitra

7
เมื่อฉันใช้ไวยากรณ์ jenkinsfile ที่ประกาศแล้วนี่ใช้ไม่ได้ข้อความแสดงข้อผิดพลาดคือ:WorkflowScript: 97: Expected a step @ line 97, column 17.
Wrench

17
ดูเหมือนว่าสิ่งนี้จะทำงานได้ในscriptบล็อกขั้นตอนเท่านั้น jenkins.io/doc/book/pipeline/syntax/#declarative-steps
ลิงทองเหลือง

51

เวอร์ชันปัจจุบันของ Pipeline รองรับreturnStdoutและreturnStatusทำให้สามารถรับเอาต์พุตหรือสถานะจากsh/ batsteps

ตัวอย่าง:

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

อย่างเป็นทางการเอกสาร


ใครสามารถช่วยฉันstackoverflow.com/questions/40946697/หรือไม่? ขอบคุณล่วงหน้า!
Jitesh Sojitra

3
งบจะถูกห่อในscript { }ขั้นตอน
x-yuri

40

คำตอบอย่างรวดเร็วคือ:

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

ฉันคิดว่ามีคำขอคุณลักษณะเพื่อให้สามารถรับผลลัพธ์ของขั้นตอนการดวลจุดโทษได้ แต่เท่าที่ฉันรู้ในปัจจุบันไม่มีตัวเลือกอื่น

แก้ไข: JENKINS-26133

EDIT2: ไม่แน่ใจตั้งแต่รุ่นใด แต่ตอนนี้ sh / bat สามารถคืนเอาต์พุต std ได้ง่ายๆ:

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

1
เช่นเดียวกันกับ FYI ขั้นตอน bat จะสะท้อนคำสั่งที่กำลังรันดังนั้นคุณต้องเริ่มต้นคำสั่ง bat ด้วย @ เพื่อรับผลลัพธ์ (เช่น "@dir")
รัสเซล Gallop

21

หากคุณต้องการได้รับ stdout และทราบว่าคำสั่งประสบความสำเร็จหรือไม่เพียงใช้returnStdoutและห่อในตัวจัดการข้อยกเว้น:

ไพพ์ไลน์สคริปต์

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

ผลลัพธ์ :

[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

น่าเสียดายที่ hudson.AbortException ไม่มีวิธีที่มีประโยชน์ใด ๆ ในการรับสถานะการออกนั้นดังนั้นหากจำเป็นต้องใช้ค่าจริงคุณจะต้องแยกมันออกจากข้อความ (ugh!)

ขัดกับ Javadoc https://javadoc.jenkins-ci.org/hudson/AbortException.htmlสร้างจะไม่ล้มเหลวเมื่อข้อยกเว้นนี้ถูกจับได้ มันล้มเหลวเมื่อไม่ได้จับ!

อัปเดต: หากคุณต้องการให้เอาต์พุต STDERR จากคำสั่งเชลล์เจนกินส์น่าเสียดายที่ไม่สามารถรองรับกรณีใช้งานทั่วไปได้อย่างถูกต้อง 2017 ตั๋วJENKINS-44930ติดอยู่ในสถานะปิงปิงที่มีความเห็นในขณะที่ยังไม่มีความคืบหน้าในการแก้ปัญหาโปรดพิจารณาเพิ่ม upvote ของคุณลงไป

สำหรับวิธีแก้ปัญหาในตอนนี้อาจมีวิธีการสองวิธีที่เป็นไปได้

a) Redirect STDERR ไปยัง STDOUT 2>&1 - แต่มันก็ขึ้นอยู่กับคุณแล้วว่าจะแยกออกจากเอาท์พุทหลักและคุณจะไม่ได้รับผลลัพธ์ถ้าคำสั่งล้มเหลว - เพราะคุณอยู่ในตัวจัดการข้อยกเว้น

b) เปลี่ยนเส้นทาง STDERR ไปยังไฟล์ชั่วคราว (ชื่อที่คุณเตรียมไว้ก่อนหน้านี้) 2>filename(แต่อย่าลืมล้างไฟล์ในภายหลัง) - เช่น รหัสหลักจะกลายเป็น:

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) ไปทางอื่นตั้งreturnStatus=trueแทนแจกจ่ายด้วยตัวจัดการข้อยกเว้นและจับผลลัพธ์ไปยังไฟล์เช่น:

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
}

ข้อแม้: รหัสข้างต้นเป็น Unix / Linux เฉพาะ - Windows ต้องการคำสั่งเชลล์ที่แตกต่างอย่างสิ้นเชิง


1
มีโอกาสที่จะได้รับผลลัพธ์เป็น "ls: ไม่สามารถเข้าถึง dir1: ไม่มีไฟล์หรือไดเรกทอรี" และไม่ใช่แค่ "hudson.AbortException: สคริปต์ส่งคืนรหัสทางออก 2"?
user2988257

ฉันไม่เห็นว่ามันจะทำงานได้อย่างไร ในการทดสอบของฉันข้อความที่ส่งออกไม่เคยได้รับมอบหมายและคาดว่าจะเป็นเช่นนี้ ข้อยกเว้นที่เกิดจากขั้นตอนของเชลล์ป้องกันไม่ให้กำหนดค่าส่งคืน
Jakub Bochenski

2
returnStatus และ returnStdout ไม่ทำงานในเวลาเดียวกันอย่างน่าเสียดาย นี่คือตั๋ว กรุณาโหวต: issues.jenkins-ci.org/browse/JENKINS-44930
Alexander Samoylov

1
@AlexanderSamoylov คุณต้องแก้ไขโดยใช้ไฟล์ในตัวเลือก (c) ด้านบน น่าเสียดายที่ผู้เขียนเครื่องมือเหล่านี้มักจะให้ความเห็นและไม่คิดล่วงหน้าสำหรับกรณีใช้งานทั่วไปอื่น ๆ 'sh' ที่นี่เป็นประเด็น
Ed Randall

1
@Ed Randall, เห็นด้วยกับคุณอย่างเต็มที่ .. นี่คือเหตุผลที่ฉันโพสต์ปัญหานี้โดยหวังว่าจะได้รับคะแนนเสียงมากขึ้นเมื่อพวกเขาเริ่มทำอะไรบางอย่าง
อเล็กซานเด Samoylov

12

นี่เป็นกรณีตัวอย่างซึ่งจะทำให้รู้สึกว่าฉันเชื่อ!

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


    echo "${commit[-1]} "

    }
}

ผมไม่ทราบว่าวิธี แต่ช่วยคำตอบของคุณผมมากขอบคุณ :)
shaharnakash

5

สำหรับผู้ที่ต้องการใช้เอาต์พุตในคำสั่งเชลล์ที่ตามมาแทนที่จะเป็น Groovy สิ่งที่ตัวอย่างเช่นนี้สามารถทำได้:

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

ฉันพบตัวอย่างในโค้ด mavenว่ามีประโยชน์มาก


-6

วิธีที่ง่ายที่สุดคือใช้วิธีนี้

my_var=`echo 2` echo $my_var ผลลัพธ์: 2

โปรดทราบว่าไม่ใช่คำพูดเดียวที่ง่ายคืออ้างกลับ (`)


อัปเดตแล้ว แต่ฉันขอแนะนำให้คุณแสดงให้เห็นว่าสิ่งเหล่านี้ควรอยู่ภายใต้การควบคุมshมิฉะนั้นผู้คนอาจคิดว่ามันเป็นเรื่องใหญ่โดยเฉพาะอย่างยิ่งหากพวกเขาไม่คุ้นเคยกับการใช้สคริปต์ทุบตี ฉันเพิ่งลองใช้กับ Jenkins ใช้ls -lแทนecho 2และใช้งานได้ ฉันเคยใช้วิธีการนี้มาก่อน แต่เคยค้นหาวิธีอื่นเนื่องจากไม่น่าเชื่อถือ ฉันมีเอาต์พุตของคำสั่งที่ซับซ้อนมากขึ้นที่จับบนเชลล์มาตรฐานด้วยวิธีนี้ แต่เมื่อย้ายไปที่เจนกินส์shตัวแปรจะไม่เก็บค่าอะไรไว้ด้วยเหตุผลบางอย่างที่ไม่ทราบสาเหตุ
Nagev
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.