Skip to Content

Shell 函数返回值小记

Table of Contents

日常难免会有些 shell 脚本编写的事情,众所周知这事儿门槛很低,再不济把要执行的命令挨排垒进去也可以作为 一个自动化脚本,但有些复杂的功能或者考虑到代码的复用就需要分些模块、封装些函数了。如何更优雅的 处理函数的返回值便成为一个比较有意思的问题。

在 Shell 函数中优雅返回

shell 脚本没什么特别的技法可言,更多的只能是靠逐步积累。这次在编写 Lego 项目命令检查函数时, 需要获取一个返回值,我期待这个返回值不仅仅表达成功与否这个 2 元的结果。但我自己又习惯 在每个脚本前面都加上 set -e 选项,它的意义在于:如果命令失败(即返回一个非零的退出状态),那么脚本将退出。

通常避免非零值的返回导致整个程序退出的方法要么把调用过程放到 $() 中,要么就是将其与 &&|| 命令放到一起,而在这后面获取函数调用的返回值,这样就保证及时返回值为非 0,程序还是能按条件往下执行。下面对后者给出一个示例:

call_some_function "${args}" || ret=$?
if [ "${ret}" = 'false' ]; then
    echo "do something"
fi

返回码小结

类 Unix 系统对返回码做了统一的规范,无论是 exit 还是 return 命令,都是统一的返回规则,这里对 这些标准的错误码(返回码)做一个简单的梳理,值得注意的是如果返回码超出规定的 0 ~ 255 这个范围,则会随机返回一个这期间的数字:

Exit Code Number Meaning Example Comments
0 命令成功完成 exit 0 当命令正确完成、返回或者退出的时候,返回码为 0
1 通常的未知错误 / Catchall for general errors let “var1 = 10 Miscellaneous errors, such as “divide by zero” and other impermissible operations
2 误用shell命令 / Misuse of shell builtins (according to Bash documentation) empty_function() {} Missing keyword or command, or permission problem (and diff return code on a failed
126 命令无法执行 / Command invoked cannot execute /dev/null Permission problem or command is not an executable
127 没有找到命令 / “command not found” illegal_command Possible problem with $PATH or a typo
128 无效的退出参数 / Invalid argument to exit exit 3.14159 exit takes only integer args in the range 0 - 255 (see first footnote)
128+n 使用Linux信号x的致命错误 / Fatal error signal “n” kill -9 $PPID of script $? returns 137 (128 + 9)
130 0使用Ctrl-C终止的命令 / Script terminated by Control-C Ctl-C Control-C is fatal error signal 2, (130 = 128 + 2, see above)
255* 规范外的退出状态 / Exit status out of range exit -1 exit takes only integer args in the range 0 - 255

Shell 相关操作摘录

最后将 Linux 文档中几个相关命令的文档摘录于此:

exit [n] Cause the shell to exit with a status of n. If n is omitted, the exit status is that of the last command executed. A trap on EXIT is executed before the shell terminates.

return [n] Causes a function to stop executing and return the value specified by n to its caller. If n is omitted, the return status is that of the last command executed in the function body. If return is executed by a trap handler, the last command used to determine the sta‐ tus is the last command executed before the trap handler. if return is executed during a DEBUG trap, the last command used to deter‐ mine the status is the last command executed by the trap handler before return was invoked. If return is used outside a function, but during execution of a script by the . (source) command, it causes the shell to stop executing that script and return either n or the exit status of the last command executed within the script as the exit status of the script. If n is supplied, the return value is its least significant 8 bits. The return status is non-zero if return is supplied a non-numeric argument, or is used outside a func‐ tion and not during execution of a script by . or source. Any command associated with the RETURN trap is executed before execution resumes after the function or script.

break [n] Exit from within a for, while, until, or select loop. If n is specified, break n levels. n must be ≥ 1. If n is greater than the number of enclosing loops, all enclosing loops are exited. The return value is 0 unless n is not greater than or equal to 1.

trap [-lp] [[arg] sigspec …] The command arg is to be read and executed when the shell receives signal(s) sigspec. If arg is absent (and there is a single sigspec) or -, each specified signal is reset to its original disposition (the value it had upon entrance to the shell). If arg is the null string the signal specified by each sigspec is ignored by the shell and by the commands it invokes. If arg is not present and -p has been supplied, then the trap commands associated with each sigspec are displayed. If no arguments are supplied or if only -p is given, trap prints the list of commands associated with each signal. The -l option causes the shell to print a list of signal names and their corresponding numbers. Each sigspec is either a signal name defined in , or a signal number. Signal names are case insensitive and the SIG prefix is optional.

If a sigspec is EXIT (0) the command arg is executed on exit from the shell. If a sigspec is DEBUG, the command arg is executed before every simple command, for command, case command, select command, every arithmetic for command, and before the first command executes in a shell function (see SHELL GRAMMAR above). Refer to the description of the extdebug option to the shopt builtin for details of its effect on the DEBUG trap. If a sigspec is RETURN, the command arg is executed each time a shell function or a script executed with the . or source builtins finishes executing.

If a sigspec is ERR, the command arg is executed whenever a pipeline (which may consist of a single simple command), a list, or a com‐ pound command returns a non-zero exit status, subject to the following conditions. The ERR trap is not executed if the failed command is part of the command list immediately following a while or until keyword, part of the test in an if statement, part of a command executed in a && or || list except the command following the final && or ||, any command in a pipeline but the last, or if the com‐ mand’s return value is being inverted using !. These are the same conditions obeyed by the errexit (-e) option.

Signals ignored upon entry to the shell cannot be trapped, reset or listed. Trapped signals that are not being ignored are reset to their original values in a subshell or subshell environment when one is created. The return status is false if any sigspec is invalid; otherwise trap returns true.

微信公众号 / Vanilla-OpenResty