在 shell 命令(不是脚本)中获得“确保”/“最终”功能?

在 shell 命令(不是脚本)中获得“确保”/“最终”功能?

我需要知道命令是成功还是失败,然后无条件地运行一些清理操作。

执行顺序命令的常规选项似乎都不适用于此:

$ mycmd.sh && rm -rf temp_files/    # correct exit status, cleanup fails if mycmd fails
$ mycmd.sh ;  rm -rf temp_files/  # incorrect exit status, always cleans up
$ mycmd.sh || rm -rf temp_files/    # correct exit status, cleanup fails if mycmd succeeds

如果我要在 shell 脚本中执行此操作,我会这样做:

#!/usr/bin/env bash
mycmd.sh
RET=$?
rm -rf temp_files
exit $RET

有没有比用分号将所有这些命令链接在一起更惯用的方法来在命令行上完成此操作?

答案1

脚本中的换行符几乎总是等同于分号:

mycmd.sh; ret=$?; rm -rf temp_files; exit $ret

回应编辑:

或者,您也可以使用 atrap和 subshel​​l:

( trap 'rm -rf temp_files' EXIT; mycmd.sh )

答案2

如果您正在寻找某些语言的副本try { } finally { },还有另一种方法:使用trap内置 shellbash和其他 POSIXy shell(请参阅 参考资料help trap)。

#!/bin/bash

# exit with this by default, if it is not set later
exit_code=0  

# the cleanup function will be the exit point
cleanup () {
  # ignore stderr from rm incase the hook is called twice
  rm -rf "temp_files/" &> /dev/null  
  # exit(code)
  exit $exit_code
}

# register the cleanup function for all these signal types (see link below)
trap cleanup EXIT ERR INT TERM

# run your other script
mycmd.sh

# set the exit_code with the real result, used when cleanup is called
exit_code=$?

了解 trap 命令的参数。

请注意,这cleanup被称为:

  • 如果发送此脚本 SIGINT 或 SIGTERM 或者按下 CTRL-C (SIGINT)
  • 如果此脚本正常退出并返回 0
  • 如果 mycmd.sh 以非零状态退出(可能不是您想要的 -ERR从陷阱的参数中删除以禁用

答案3

zsh

{mycmd.sh} always {rm -rf temp_files}

总是即使出现错误(如不匹配的 glob 或运行时语法错误),该部分也会执行,从而退出脚本。

答案4

我现在只使用&&||运算符而不是if;then。但有时回到“如果;那么”会更清楚。这是其中之一,因为您需要命令行解决方案。

我会像这样重写它......

$ if mycmd.sh; then { success; actions; } else { fail; actions; } fi;  rm -rf temp_files/
  • mycmd.sh 运行并if使用其结果
  • 大括号确保内部的多个命令列表作为一个块进行处理,并且增强了清晰度。每个命令(包括最后一个)后面的大括号和分号周围的空格是强制性的。
  • 由于rm发生在 之后fi,因此它将无条件执行。

相关内容