Capistrano & Bash:忽略命令退出状态

Posted

技术标签:

【中文标题】Capistrano & Bash:忽略命令退出状态【英文标题】:Capistrano & Bash: ignore command exit status 【发布时间】:2010-10-20 00:22:35 【问题描述】:

我正在使用 Capistrano 运行远程任务。我的任务如下所示:

task :my_task do
  run "my_command"
end

我的问题是,如果my_command 的退出状态为 != 0,则 Capistrano 认为它失败并退出。当退出状态不是 0 时,如何让 capistrano 继续运行?我已将 my_command 更改为 my_command;echo 并且它可以工作,但感觉就像一个 hack。

【问题讨论】:

【参考方案1】:

最简单的方法是在命令末尾附加 true。

  task :my_task do
    run "my_command"
  end

变成

  task :my_task do
    run "my_command; true"
  end

【讨论】:

不确定 capistano 是什么,但由于 bash 存在同样的问题,我在这里找到了方法。然后你可以使用“my_command || true”而不是“my_command; true”【参考方案2】:

对于 Capistrano 3,您可以(如建议 here)使用以下内容:

execute "some_command.sh", raise_on_non_zero_exit: false

【讨论】:

非常好的选择!【参考方案3】:

+grep+ 命令根据它找到的内容以非零值退出。在您关心输出但不介意它是否为空的用例中,您将默默地丢弃退出状态:

run %Qbash -c 'grep #escaped_grep_command_args ; true' 

通常,我认为第一个解决方案很好——我会让它自己记录:

cmd = "my_command with_args escaped_correctly"
run %Qbash -c '#cmd || echo "Failed: [#cmd] -- ignoring."'

【讨论】:

【参考方案4】:

如果您希望 Capistrano 代码对退出代码执行不同的操作,则需要修补它;如果退出状态不为零,则通过硬编码引发异常。

这是 lib/capistrano/command.rb 的相关部分。以if (failed... 开头的那一行是重要的。基本上它说如果有任何非零返回值,就会引发错误。

# Processes the command in parallel on all specified hosts. If the command
# fails (non-zero return code) on any of the hosts, this will raise a
# Capistrano::CommandError.
def process!
  loop do
    break unless process_iteration  @channels.any?  |ch| !ch[:closed]  
  end

  logger.trace "command finished" if logger

  if (failed = @channels.select  |ch| ch[:status] != 0 ).any?
    commands = failed.inject()  |map, ch| (map[ch[:command]] ||= []) << ch[:server]; map 
    message = commands.map  |command, list| "#command.inspect on #list.join(',')" .join("; ")
    error = CommandError.new("failed: #message")
    error.hosts = commands.values.flatten
    raise error
  end

  self
end

【讨论】:

我猜这只适用于 Capistrano 2,对于 Capistrano 3,你可以使用Ciryon’s answer【参考方案5】:

我找到了最简单的方法:

run "my_command || :"

注意:: 是 NOP 命令,因此退出代码将被简单地忽略。

【讨论】:

【参考方案6】:

我只是将 STDERR 和 STDOUT 重定向到 /dev/null,所以你的

run "my_command"

变成

run "my_command > /dev/null 2> /dev/null"

这非常适用于标准 unix 工具,例如 cp 或 ln 可能会失败,但您不想在此类失败时停止部署。

【讨论】:

【参考方案7】:

我不确定他们添加此代码的版本,但我喜欢使用 raise_on_non_zero_exit 处理此问题

namespace :invoke do
  task :cleanup_workspace do
    on release_roles(:app), in: :parallel do
      execute 'sudo /etc/cron.daily/cleanup_workspace', raise_on_non_zero_exit: false
    end
  end
end

这里是该功能在 gem 中实现的地方。 https://github.com/capistrano/sshkit/blob/4cfddde6a643520986ed0f66f21d1357e0cd458b/lib/sshkit/command.rb#L94

【讨论】:

以上是关于Capistrano & Bash:忽略命令退出状态的主要内容,如果未能解决你的问题,请参考以下文章

Capistrano 和几个 SSH 密钥

资产预编译 Capistrano 3.4

Rails 5.1 Capistrano 使用 secrets.yml.key 部署

当通过 NVM 安装 NPM 时,Capistrano 部署失败并出现 react_on_rails

如何在 Capistrano 中切换远程用户

将文件重命名为 md5 sum + 扩展名 (BASH)