Day by Day, Site by Site

Open source, Some Code, Troubleshooting, Good Links

Jun 15, 2020 - devops

Экранирование симоволов в Groovy (Jenkins pipeline)

В задании Jenkins есть такое определение:

def pR = sh(script: "cd $IT; PLAN=\$(terragrunt plan --terragrunt-source-update | landscape);
                    echo "$PLAN"; CHANGES=$(echo "$PLAN" | tail -2); echo $CHANGES")

Возникает ошибка когда идет попытка выполнить echo "$PLAN":

solution: either escape a literal dollar sign "\$5" or bracket the value
expression "${5}" @ line 34, column 148.
ce-update | landscape); echo "$PLAN"; CH

Для понимания почему возникает ошибка нужно рассмотреть механику работы декларативного конвеера (declarative pipeline) в Jenkins. Декларативный конвеер в Jenkins это скрипт на Groovy. Groovy, по сути, это командный интерпретатор аналогичный Bash. Принципы работы схож с другими интерпретаторами.

После того как Jenkins начинает выполнять задание, Groovy интерпретатор начинает последовательно исполнять команды Groovy cкрипта. Когда доходит до места исполнения команд Shell, происходит запуск нового экземпляра Shell (подпроцесса) в котором происходит запуск команд Shell. К этому моменту Groovy интерпретатор должен уже преобразовать все переменные которые ему встретились. Поэтому он преобразовывывает в том числе переменные которые относятся к Bash командам. А так как этих переменных в его среде окружения нет, то возникает ошибка выше.

Таким образом, для строк с двойными кавычками, Groovy процессор будет преобразовывать строку первым. И только после преобразования переменных Groovy, запустится отдельный подпроцесс, где преобразованием переменных займется уже Bash.

IT, PLAN, CHANGES переменные среды исполнения (runtime variable) Bash, а не переменные среды исполнения Groovy. Во время преобразования переменных IT, PLAN, CHANGES Groovy не может найти соответствующие переменные из набора переменных.

Поэтому, что бы Groovy не смог их интерпретировать, нужно экранировать все "$", если используется двойные кавычки, как в данном случае:

def pR = sh(script: "cd \$IT; PLAN=\$(terragrunt plan --terragrunt-source-update | landscape);
                    echo \$PLAN; CHANGES=\$(echo \$PLAN | tail -2); echo \$CHANGES")

Или использовать одиночные кавычки, которые не используют преобразования:

def pR = sh(script: 'cd $IT; PLAN=$(terragrunt plan --terragrunt-source-update | landscape);
                    echo $PLAN; CHANGES=$(echo $PLAN | tail -2); echo $CHANGES')

Использованная литература - Stackoverflow One, Stackoverflow Second