Как получить выходные данные команды оболочки, выполненной с использованием в переменную из Jenkinsfile (groovy)?

213

У меня есть что-то подобное в Jenkinsfile (Groovy), и я хочу записать stdout и код выхода в переменную, чтобы позже использовать эту информацию.

sh "ls -l"

Как я могу это сделать, особенно если учесть, что вы не можете запустить какой-либо отличный код внутри Jenkinsfile?

Сорин
источник
2
Дубликат stackoverflow.com/questions/36507410/… .
Джесси Глик

Ответы:

393

Последняя версия 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 в качестве имени переменной без префикса, все в порядке.
Бастиан Фойгт
Пожалуйста, помогите мне для stackoverflow.com/questions/40946697/…
Джитеш Соджитра
7
Когда я использую декларативный синтаксис jenkinsfile, это не работает, появляется сообщение об ошибке:WorkflowScript: 97: Expected a step @ line 97, column 17.
Wrench
17
Кажется, что это работает только внутри scriptблока шага. jenkins.io/doc/book/pipeline/syntax/#declarative-steps
медная обезьяна
51

Текущая версия конвейера изначально поддерживает returnStdoutи returnStatus, что позволяет получить вывод или статус из sh/ batsteps.

Пример:

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

Официальная документация .

luka5z
источник
Может ли кто-нибудь помочь мне для stackoverflow.com/questions/40946697/… ? Заранее спасибо!
Джитеш Соджитра
3
Заявления должны быть обернуты в script { }шаг.
x-
40

быстрый ответ таков:

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

Я думаю, что существует запрос функции, чтобы можно было получить результат шага sh, но, насколько я знаю, в настоящее время нет другого варианта.

РЕДАКТИРОВАТЬ: JENKINS-26133

РЕДАКТИРОВАТЬ 2: Не совсем уверен, с какой версией, но шаги sh / bat теперь могут возвращать вывод std, просто:

def output = sh returnStdout: true, script: 'ls -l'
vehovmar
источник
1
Также, к вашему сведению, шаги bat повторяют выполняемую команду, поэтому вам нужно запустить команды bat с @, чтобы просто получить вывод (например, "@dir").
Рассел Галоп
21

Если вы хотите получить стандартный вывод и знать, была ли команда выполнена успешно или нет, просто используйте 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 отсутствует какой-либо полезный метод для получения этого статуса выхода, поэтому, если требуется фактическое значение, вам нужно разобрать его в сообщении (тьфу!)

В отличие от Javadoc, https://javadoc.jenkins-ci.org/hudson/AbortException.html сборка не завершается при обнаружении этого исключения. Это терпит неудачу, когда это не поймано!

Обновление: если вы также хотите получить вывод STDERR из команды оболочки, к сожалению, Jenkins не сможет должным образом поддерживать этот общий вариант использования. Билет на 2017 год JENKINS-44930 застрял в состоянии самоуверенного пинг-понга, пока не продвинулся в поиске решения - рассмотрите возможность добавления к нему своего положительного голоса.

Что касается решения сейчас , может быть несколько возможных подходов:

а) Перенаправить STDERR в STDOUT 2>&1 - но тогда вам придется проанализировать это из основного вывода, и вы не получите вывод, если команда не удалась - потому что вы находитесь в обработчике исключений.

б) перенаправить 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
Я не понимаю, как это могло сработать. В моем тестировании выходной текст никогда не назначался, и этого следовало ожидать. Исключение, выброшенное из шага оболочки, не позволяет присвоить возвращаемое значение
Якуб Боченски,
2
returnStatus и returnStdout, к сожалению, не работают одновременно. Вот билет. Пожалуйста, проголосуйте: questions.jenkins-ci.org/browse/JENKINS-44930 .
Александр Самойлов
1
@AlexanderSamoylov Вы должны обойти, используя файл, как в варианте (с) выше. К сожалению, авторы этих инструментов часто самоуверенны и не думают заранее о других распространенных случаях использования, в данном случае «sh».
Эд Рэндалл
1
@Ed Randall, Полностью с тобой согласен .. Вот почему я опубликовал этот выпуск в надежде, что из-за большого количества голосов они начнут что-то делать.
Александр Самойлов
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 весьма полезными.

Nagev
источник
-6

Самый простой способ - использовать этот способ

my_var=`echo 2` echo $my_var выход: 2

обратите внимание, что это не простая одинарная кавычка - обратная кавычка (`).

Аджай Гадхавана
источник
Проголосовано, но я бы посоветовал вам показать, что они должны быть обернуты, shиначе люди могут подумать, что это здорово, особенно если они не знакомы с сценариями bash. Я только что попробовал это на Дженкинсе, используя ls -lвместо, echo 2и это работает. Я действительно использовал этот подход раньше, но искал альтернативу, потому что он не очень надежен. У меня есть вывод более сложной команды, захваченной таким образом в стандартной оболочке, но при портировании в Jenkins shпеременная не содержит ничего по неизвестной причине.
Нагев