【发布时间】:2012-01-16 00:21:43
【问题描述】:
我已经看到 bash 脚本中使用“exit”和“exec”来在发生错误时停止脚本执行。例如:
if [ ! -f file ]; then
echo "no file"
exit 1
fi
和:
if [ ! -f file ]; then
exec echo "no file"
fi
这里的最佳做法是什么?为什么?也欢迎有关“执行”和“退出”的更广泛讨论/解释:)
【问题讨论】:
我已经看到 bash 脚本中使用“exit”和“exec”来在发生错误时停止脚本执行。例如:
if [ ! -f file ]; then
echo "no file"
exit 1
fi
和:
if [ ! -f file ]; then
exec echo "no file"
fi
这里的最佳做法是什么?为什么?也欢迎有关“执行”和“退出”的更广泛讨论/解释:)
【问题讨论】:
exit 只是退出 shell,将指定的数字退出代码(如果省略,则返回 0)返回给父进程。它相当于 C 库例程也称为 exit,或从 main 返回。
exec 用新的可执行映像替换 shell(仍在同一进程中运行),该映像将在适当的时候退出并将一些代码或其他代码返回给父进程。大致相当于C库例程execvp。
您的第一个示例几乎是但不完全是在发生错误时停止脚本的正确方法。它应该是
if [ ! -f file ]; then
echo "no file" >&2
exit 1
fi
您的示例中缺少>&2,导致错误消息转到它所属的stderr,而不是不属于它的stdout。
你的第二个例子是错误。除了错误信息出现在错误的地方之外,exec echo 将停止脚本(因为/bin/echo 将执行它的操作然后退出)但它会将退出代码 0 返回给父进程。退出代码 0 表示成功。在 Unix 环境中运行的程序必须始终确保在失败时返回一个非零退出代码。
exec 的正确用法是在 shell 脚本中进行一些设置工作,然后调用用另一种语言编写的长期存在的程序,之后没有任何事情可做,因此保留shell进程挂在身边。例如:
#! /bin/sh
PATH=/special/directory/for/foo:$PATH
export PATH
exec foo
【讨论】:
export他们。如果没有exec,则有两个PID,shell 挂起占用RAM,你必须记住在下一行写exit $? 以获取传播到祖父进程的退出代码。就是这样。
exit $? 吗?检查这两个示例:pastebin.com/Sax5SVGa 如您所见,在第二个示例中,我没有使用 exec,但仍然得到了正确的退出代码。还是我误会了你?
命令exit 使用给定的退出代码退出当前shell。命令exec 用参数定义的新进程替换当前shell。这也有效地在进程终止后终止脚本,退出代码是新进程的退出代码。
第一个代码 sn-ps 调用内部 shell 命令echo,然后以退出代码 1 终止 shell。第二个代码用外部程序 echo 替换 shell,它可能会以退出代码终止0.
我肯定会推荐第一个变体。它节省了启动外部命令/bin/echo 并正确指示退出代码的错误。
【讨论】:
指示错误的正确方法是让脚本返回一个非零代码,例如 1。 在您的情况下,最好的方法是使用“exit 1”。
使用“exec”将简单地执行它之后的代码。也许您看到的示例是使用“#!/bin/bash -e”或“set -e”,然后使用“exec”调用失败的代码,从而导致“exec”本身返回非零代码,并且“-e”表示如果任何命令返回非零代码或计算结果为假,则立即退出脚本。
【讨论】:
exec 用新进程替换当前 shell,有效地终止脚本,不管 set -e 或类似的。