简体   繁体   English

Shell执行程序如何运行脚本?

[英]How does the Shell executor run scripts?

We've recently moved to Gitlab and have started using pipelines. 我们最近搬到了Gitlab,并开始使用管道。 We've set up a build server (an Ubuntu 16.04 instance) and installed a runner that uses a Shell executor but I'm unsure of how it actually executes the scripts defined in the .gitlab-ci.yml file. 我们已经设置了一个构建服务器(一个Ubuntu 16.04实例),并安装了一个使用Shell执行程序的运行程序,但是我不确定它如何实际执行.gitlab-ci.yml文件中定义的脚本。 Consider the following snippet of code: 考虑以下代码片段:

script:
    - sh authenticate.sh $DEPLOY_KEY
    - cd MAIN && sh deploy.sh && cd .. 
    - sh deploy_service.sh MATCHMAKING
    - sh deauthenticate.sh

I was under the impression that it will just pipe these commands to Bash, and hence I was expecting the default Bash behaviour. 我的印象是它将这些命令通过管道传递给Bash,因此我期待默认的Bash行为。 What happens, however, is that the deploy.sh fails because of an ssh error ; 但是,由于ssh错误,导致deploy.sh失败了; Bash then continues to execute deploy_service.sh (which is expected behaviour) however this fails with a can't open deploy_service.sh error and the job terminates without Bash executing the last statement. Bash然后继续执行deploy_service.sh (这是预期的行为),但是由于无法can't open deploy_service.sh错误而失败,并且作业在没有Bash执行最后一条语句的情况下终止。

From what I understand, Bash will only abort on error if you do a set -e first and hence I was expecting all the statements to be executed. 据我了解,如果您先执行set -e ,Bash只会在出错时中止,因此我期望所有语句都将被执行。 I've tried adding the set -e as the first statement but this makes no difference whatsoever - it doesn't terminate on the first ssh error. 我尝试将set -e作为第一条语句添加,但这没有任何区别-它不会在第一个ssh错误时终止。

I've added the exact output from Gitlab below: 我在下面添加了来自Gitlab的确切输出:

Without set -e 没有set -e

$ cd MAIN && sh deploy.sh && cd ..
deploy.sh: 72: deploy.sh: Bad substitution
Building JS bundles locally...

> better-npm-run build

running better-npm-run in x
Executing script: build

to be executed: node ./bin/build 
-> building js bundle...
-> minifying js bundle...
Uploading JS bundles to server temp folder...
COMMENCING RESTART. 5,4,3,2,1...
ssh: Could not resolve hostname $: Name or service not known
$ sh deploy_service.sh MATCHMAKING
sh: 0: Can't open deploy_service.sh
ERROR: Job failed: exit status 1

With set -e 带有set -e

$ set -e
$ cd MAIN && sh deploy.sh && cd ..
deploy.sh: 72: deploy.sh: Bad substitution
Building JS bundles locally...

> better-npm-run build

running better-npm-run in x
Executing script: build

to be executed: node ./bin/build 
-> building js bundle...
-> minifying js bundle...
Uploading JS bundles to server temp folder...
COMMENCING RESTART. 5,4,3,2,1...
ssh: Could not resolve hostname $: Name or service not known
$ sh deploy_service.sh MATCHMAKING
sh: 0: Can't open deploy_service.sh
ERROR: Job failed: exit status 1

Why is it, without set -e , terminating on error (also, why is it terminating on the second error only and not the ssh error)? 为什么在没有set -e情况下以错误终止(也为什么仅在第二个错误而不是ssh错误终止)? Any insights would be greatly appreciated. 任何见解将不胜感激。

Gitlab script block is actuality an array of shell scripts. Gitlab脚本块实际上是外壳脚本的数组。 https://docs.gitlab.com/ee/ci/yaml/#script Failure in each element of array will fail a whole array. https://docs.gitlab.com/ee/ci/yaml/#script数组中每个元素的失败将使整个数组失败。 To workaround put your script block in some script.sh file 要解决此问题,请将您的脚本块放在一些script.sh文件中

like 喜欢

script:
    - ./script.sh

I don't think your sh deploy.sh is generating a non-zero exit code. 我认为您的sh deploy.sh不会生成非零的退出代码。

You are using set -e to tell the current process to exit if a command exits with a non-zero return code, but you are creating a sub-process to run the shell script. 您正在使用set -e告诉当前进程退出(如果命令以非零返回码退出),但是您正在创建一个子进程来运行Shell脚本。

Here's a simple example script that I've called deploy.sh : 这是我称为deploy.sh的简单示例脚本:

#!/bin/bash
echo "First."
echox "Error"
echo "Second"

If I run the script, you can see how the error is not handled: 如果我运行脚本,则可以看到错误的处理方式:

$ sh deploy.sh 
First.
deploy.sh: line 5: echox: command not found
Second

If I run set -e first, you will see it has no effect. 如果我先运行set -e ,您将看不到它的作用。

$ set -e
$ sh deploy.sh 
First.
deploy.sh: line 5: echox: command not found
Second

Now, I add -e to the /bin/bash shebang: 现在,我将-e添加到/bin/bash shebang中:

#!/bin/bash -e
echo "First."
echox "Error"
echo "Second"

When I run the script with sh the -e still takes no effect. 当我使用sh运行脚本时, -e 仍然无效。

$ sh ./deploy.sh 
First.
./deploy.sh: line 3: echox: command not found
Second

When this script is run directly using bash, the -e takes effect. 使用bash直接运行此脚本时, -e生效。

$ ./deploy.sh 
First.
./deploy.sh: line 3: echox: command not found

To fix your issue I believe you need to: 要解决您的问题,我相信您需要:

  • Add -e to the script shebang line ( #!/bin/bash -e ) -e添加到脚本shebang行( #!/bin/bash -e
  • Call the script direct from bash using ./deploy.sh and not run the script through sh . 使用./deploy.sh直接从bash调用脚本,而不通过sh运行脚本。

Bear in mind that if deploy.sh does fail then the cd .. will not run ( && means run the next command if the preceding one succeeded), which would mean you were in the wrong directory to run the deploy_service.sh . 请记住,如果deploy.sh 确实失败,则cd ..不会运行( &&表示如果前一个命令成功,则运行下一个命令),这意味着您位于错误的目录中,无法运行deploy_service.sh You would be better with cd MAIN; sh deploy.sh; cd .. 使用cd MAIN; sh deploy.sh; cd ..会更好cd MAIN; sh deploy.sh; cd .. cd MAIN; sh deploy.sh; cd .. cd MAIN; sh deploy.sh; cd .. , but I suggest replacing your call to deploy.sh with simpler alternative: cd MAIN; sh deploy.sh; cd .. ,但是我建议用更简单的替代方法替换对deploy.sh的调用:

script:
  - sh authenticate.sh $DEPLOY_KEY
  - (cd MAIN && sh deploy.sh) 
  - sh deploy_service.sh MATCHMAKING
  - sh deauthenticate.sh

This is not wildly different, but will result in the cd MAIN && sh deploy.sh to be run in a sub-process (that's what the brackets do), which means that the current directory of the overall script is not affected. 这没有什么大不相同,但是将导致cd MAIN && sh deploy.sh在子进程中运行(括号是这样做的),这意味着整个脚本的当前目录不受影响。 Think of it like "spawn a sub-process, and in the sub-process change directory and run that script", and when the sub-process finishes you end up where you started. 可以将其想象为“生成一个子流程,并在子流程的更改目录中并运行该脚本”,并且当该子流程完成时,您将在开始的地方结束。

As other users have commented, you're actually running your scripts in sh, not bash, so all round this might be better: 正如其他用户所评论的那样,您实际上是在sh而不是bash中运行脚本,因此全面来看可能会更好:

script:
  - ./authenticate.sh $DEPLOY_KEY
  - (cd MAIN && ./deploy.sh) 
  - ./deploy_service.sh MATCHMAKING
  - ./deauthenticate.sh

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM