为什么相同的命令在 GitLab CI 中失败?

Why same command fails in GitLab CI?

以下命令在终端上运行完美,但在 GitLab 中同样的命令失败 CI。

echo Hello >> foo.txt; cat foo.txt | grep "test"; [[ $? -eq 0 ]] && echo fail || echo success

return 是 success 但 GitLab 中的相同命令 CI

$ echo Hello >> foo.txt; cat foo.txt | grep "test"; [[ $? -eq 0 ]] && echo fail || echo success
Cleaning up file based variables
ERROR: Job failed: command terminated with exit code 1

简直是失败了。我不知道为什么。 echo $SHELL return /bin/bash 都在。

问题来源

考虑到 CI 上下文中的“隐含”set -e,您观察到的行为非常标准。

更准确地说,您的代码包含三个复合命令:

echo Hello >> foo.txt
cat foo.txt | grep "test"
[[ $? -eq 0 ]] && echo fail || echo success 

grep "test" 命令 return 是一个非零退出代码(即 1)。结果,脚本立即退出,最后一行没有执行。

请注意,此功能在 CI 上下文中很典型,因为如果某个中间命令在复杂脚本中失败,我们通常希望失败,并避免 运行 下一个命令(考虑到错误可能是“题外话”)。

您也可以在本地复制,例如:

bash -e -c "
echo Hello >> foo.txt
cat foo.txt | grep "test"
[[ $? -eq 0 ]] && echo fail || echo success 
"

这主要等同于:

bash -c "
set -e
echo Hello >> foo.txt
cat foo.txt | grep "test"
[[ $? -eq 0 ]] && echo fail || echo success 
"

相关手册页

更多见解:

如何解决这个问题?

您应该采用另一种措辞,避免 [[ $? -eq 0 ]] 事后检验。因此,可能 return 非零退出代码而不意味着失败的命令应该受到一些 if:

的“保护”
echo Hello >> foo.txt
if cat foo.txt | grep "test"; then
  echo fail
  false  # if ever you want to "trigger a failure manually" at some point.
else
  echo success
fi

此外,请注意 grep "test" foo.txtcat foo.txt | grep "test" 更加地道——这正是 UUOC 的一个实例(无用的使用猫)。

I have no idea why.

Gitlab 一次执行一个命令,并检查每个命令的退出状态。当退出状态不为零时,作业失败。

foo.txt 中没有 test 字符串,因此命令 cat foo.txt | grep "test" 以非零退出状态退出。因此作业失败。