shell 脚本中的陷阱处理和隐式子 shell

lar*_*sks 14 shell trap

假设您有一个 shell 脚本,它通过EXIT陷阱运行某种清理代码,如下所示:

#!/bin/bash

mytrap () {
  echo "It's a trap!" >&2
}

trap mytrap exit

echo I am at the end of the script.
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,这将It's a trap!在脚本退出时打印出来:

$ sh myscript
I am at the end of the script.
It's a trap!
Run Code Online (Sandbox Code Playgroud)

您修改脚本以添加一个函数,该函数生成一些最终通过管道传输到另一个命令的输出,如下所示:

#!/bin/bash

mytrap () {
  echo "It's a trap!" >&2
}

myfunc () {
  echo "I've got a bad feeling about this..."
}

trap mytrap exit

myfunc | cat > /dev/null

echo I am at the end of the script.
Run Code Online (Sandbox Code Playgroud)

由于管道,代码在myfunc子shell中运行......并且子shell似乎没有继承trap父级的行为,这意味着如果您在这里执行任何应该由您的陷阱代码清除的操作,不会发生。

所以你试试这个:

myfunc () {
  trap mytrap EXIT
  echo "I've got a bad feeling about this..."
}
Run Code Online (Sandbox Code Playgroud)

并且mytrap在子shell退出时仍然无法触发。事实证明,您需要一个明确的exit,如下所示:

myfunc () {
  trap mytrap EXIT
  echo "I've got a bad feeling about this..."
  exit
}
Run Code Online (Sandbox Code Playgroud)

使用上面的代码,mytrap将在退出子shell时适当触发:

$ sh myscript 
It's a trap!
I am at the end of the script.
It's a trap!
Run Code Online (Sandbox Code Playgroud)

这是预期的行为吗?我对这里的几件事感到惊讶:

  • trap 设置没有被子shell继承
  • 从子shell隐式退出似乎不会触发EXIT 陷阱

JRF*_*son 8

bashtrap内置允许关键字RETURN. 因此改变:

trap mytrap EXIT
Run Code Online (Sandbox Code Playgroud)

到:

trap mytrap RETURN
Run Code Online (Sandbox Code Playgroud)

见的讨论trap中壳内建