Làm cách nào để tôi nhận được đầu ra của lệnh shell được thực thi bằng cách sử dụng vào một biến từ Jenkinsfile (groovy)?


213

Tôi có một cái gì đó như thế này trên Jenkinsfile (Groovy) và tôi muốn ghi lại thiết bị xuất chuẩn và mã thoát trong một biến để sử dụng thông tin sau này.

sh "ls -l"

Làm thế nào tôi có thể làm điều này, đặc biệt là dường như bạn không thể thực sự chạy bất kỳ loại mã Groovy nào bên trong Jenkinsfile?



Câu trả lời:


390

Phiên bản mới nhất của shbước đường ống cho phép bạn thực hiện các thao tác sau;

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

Một tính năng khác là returnStatustùy chọn.

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

Các tùy chọn này mà thêm vào dựa trên này vấn đề.

Xem tài liệu chính thức cho shlệnh.


11
Có vẻ như bây giờ nó được ghi lại -> jenkins.io/doc/pipeline/steps/workflow-durable-task-step/ phỏng
zot24

Không làm việc cho tôi với tiền tố "vars" mặc dù. Khi tôi chỉ sử dụng GIT_COMMIT_EMAIL làm tên var mà không có tiền tố thì tất cả đều ổn.
Bastian Voigt

Xin hãy giúp tôi về stackoverflow.com/questions
40946697 / Từ

6
Khi tôi đang sử dụng cú pháp jenkinsfile khai báo, điều này không hoạt động, thông báo lỗi là:WorkflowScript: 97: Expected a step @ line 97, column 17.
Cờ lê

16
Có vẻ như điều này chỉ hoạt động trong một scriptkhối bước. jenkins.io/doc/book/pipeline/syntax/#declarative-steps
khỉ đồng

51

Phiên bản Pipeline hiện tại vốn hỗ trợ returnStdoutreturnStatus, giúp có thể nhận đầu ra hoặc trạng thái từ sh/ batbước.

Một ví dụ:

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

Một tài liệu chính thức .


Ai đó có thể giúp tôi về stackoverflow.com/questions/40946697/ không? Cảm ơn trước!
Jitesh Sojitra

2
Các báo cáo sẽ được gói trong một script { }bước.
x-yuri

40

câu trả lời nhanh là đây:

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

Tôi nghĩ rằng có một yêu cầu tính năng để có thể nhận được kết quả của bước sh, nhưng theo tôi biết, hiện tại không có lựa chọn nào khác.

EDIT: JENKIN-26133

EDIT2: Không hoàn toàn chắc chắn kể từ phiên bản nào, nhưng các bước sh / bat bây giờ có thể trả về đầu ra tiêu chuẩn, chỉ đơn giản là:

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

1
Ngoài ra FYI, các bước bat lặp lại lệnh đang được chạy, do đó bạn cần bắt đầu các lệnh bat với @ để chỉ nhận đầu ra (ví dụ: "@dir").
Russell Gallop

21

Nếu bạn muốn nhận được thiết bị xuất chuẩn VÀ biết liệu lệnh có thành công hay không, chỉ cần sử dụng returnStdoutvà bọc nó trong một trình xử lý ngoại lệ:

đường ống dẫn

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

đầu ra :

[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

Thật không may hudson.AbortException thiếu bất kỳ phương thức hữu ích nào để có được trạng thái thoát đó, vì vậy nếu giá trị thực tế là bắt buộc, bạn cần phải phân tích nó ra khỏi tin nhắn (ugh!)

Trái ngược với Javadoc https://javadoc.jenkins-ci.org/hudson/AbortException.html việc xây dựng không bị thất bại khi ngoại lệ này bị bắt. Nó thất bại khi nó không bị bắt!

Cập nhật: Nếu bạn cũng muốn đầu ra STDERR từ lệnh shell, Jenkins không may không hỗ trợ đúng trường hợp sử dụng thông thường đó. Một vé năm 2017 JENKINS-44930 bị kẹt trong tình trạng bóng bàn gây tranh cãi trong khi không có tiến triển nào đối với giải pháp - vui lòng xem xét việc thêm upvote của bạn vào đó.

Như một giải pháp bây giờ , có thể có một vài cách tiếp cận có thể:

a) Chuyển hướng STDERR sang STDOUT 2>&1 - nhưng sau đó, bạn phải phân tích ra khỏi đầu ra chính và bạn sẽ không nhận được đầu ra nếu lệnh thất bại - vì bạn đang xử lý ngoại lệ.

b) chuyển hướng STDERR sang một tệp tạm thời (tên mà bạn chuẩn bị trước đó) 2>filename(nhưng nhớ làm sạch tệp sau đó) - tức là. mã chính trở thành:

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) Đi theo cách khác, returnStatus=truethay vào đó, phân phối với trình xử lý ngoại lệ và luôn luôn bắt đầu ra thành một tệp, nghĩa là:

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
}

Hãy cẩn thận: đoạn mã trên là dành riêng cho Unix / Linux - Windows yêu cầu các lệnh shell hoàn toàn khác nhau.


1
có cơ hội nhận được đầu ra là "ls: không thể truy cập dir1: Không có tệp hoặc thư mục như vậy" và không chỉ là "hudson.AbortException: script trả về mã thoát 2"?
dùng2988257

Tôi không thấy làm thế nào điều này có thể làm việc. Trong thử nghiệm của tôi, văn bản đầu ra không bao giờ được chỉ định và điều này được mong đợi. Ngoại lệ được ném từ bước shell ngăn giá trị trả về được gán
Jakub Bochenski

2
returnStatus và returnStdout không hoạt động cùng một lúc không may. Đây là vé. Vui lòng, bỏ phiếu: problems.jenkins-ci.org/browse/JENKINS-44930 .
Alexander Samoylov

1
@AlexanderSamoylov Bạn phải xử lý một tệp như trong tùy chọn (c) ở trên. Thật không may, các tác giả của các công cụ này thường bị tranh cãi và không nghĩ trước cho các trường hợp sử dụng phổ biến khác, 'sh' ở đây là một trường hợp điển hình.
Ed Randall

1
@Ed Randall, Hoàn toàn đồng ý với bạn .. Đây là lý do tại sao tôi đăng vấn đề này với hy vọng rằng do số lượng phiếu bầu lớn hơn, họ bắt đầu làm một cái gì đó.
Alexander Samoylov

12

Đây là một trường hợp mẫu, sẽ có ý nghĩa tôi tin!

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


    echo "${commit[-1]} "

    }
}

Tôi không biết đường nhưng câu trả lời của bạn giúp tôi rất nhiều, cảm ơn bạn :)
shaharnakash 26/07/17

5

Đối với những người cần sử dụng đầu ra trong các lệnh shell tiếp theo, thay vì Groovy, một số thứ như ví dụ này có thể được thực hiện:

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

Tôi thấy các ví dụ về mã maven khá hữu ích.


-6

Cách dễ nhất là sử dụng cách này

my_var=`echo 2` echo $my_var đầu ra: 2

lưu ý rằng không phải là trích dẫn đơn giản là trích dẫn trở lại (`).


Được khuyến khích, nhưng tôi khuyên bạn nên chứng minh rằng những thứ này nên được gói gọn trong một shtrường hợp khác mọi người có thể nghĩ nó thật hấp dẫn, đặc biệt nếu họ không quen với kịch bản bash. Tôi vừa thử nó trên Jenkins, sử dụng ls -lthay vì echo 2và nó hoạt động. Tôi đã thực sự sử dụng phương pháp này trước đây, nhưng đã tìm kiếm một giải pháp thay thế bởi vì, nó không đáng tin cậy lắm. Tôi có đầu ra của một lệnh phức tạp hơn được ghi lại trên một vỏ tiêu chuẩn theo cách này, nhưng khi được chuyển đến Jenkins sh, biến không giữ được gì, vì một số lý do không xác định.
Nagev
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.