1. 程式人生 > >Linux Shell Bash 帶有特殊含義的退出碼

Linux Shell Bash 帶有特殊含義的退出碼

混淆 c++程序員 att fork ref onos with -cp nav

Linux Shell Bash 帶有特殊含義的退出碼

用途說明

exit命令用於退出當前shell,在shell腳本中可以終止當前腳本執行。

常用參數

格式:exit n

退出。設置退出碼為n。(Cause the shell to exit with a status of n.)

格式:exit

退出。退出碼不變,即為最後一個命令的退出碼。(If n is omitted, the exit status is that of the last command executed. )

格式:$?

上一個命令的退出碼。

格式:trap "commands" EXIT

退出時執行commands指定的命令。( A trap on EXIT is executed before the shell terminates.)

退出碼(exit status,或exit code)的約定:

0表示成功(Zero - Success)

非0表示失敗(Non-Zero - Failure)

2表示用法不當(Incorrect Usage)

127表示命令沒有找到(Command Not Found)

126表示不是可執行的(Not an executable)

>=128 信號產生

man 3 exit 寫道 The C standard specifies two constants, EXIT_SUCCESS and EXIT_FAILURE, that may be passed to exit() to indicate
successful or unsuccessful termination, respectively.

以下摘自/usr/include/stdlib.h

C代碼 技術分享圖片
  1. #define EXIT_FAILURE 1 /* Failing exit status. */
  2. #define EXIT_SUCCESS 0 /* Successful exit status. */

BSD試圖對退出碼標準化。

man 3 exit 寫道 BSD has attempted to standardize exit codes; see the file <sysexits.h>.

以下摘自/usr/include/sysexits.h

C代碼 技術分享圖片
  1. #define EX_OK 0 /* successful termination */
  2. #define EX__BASE 64 /* base value for error messages */
  3. #define EX_USAGE 64 /* command line usage error */
  4. #define EX_DATAERR 65 /* data format error */
  5. #define EX_NOINPUT 66 /* cannot open input */
  6. #define EX_NOUSER 67 /* addressee unknown */
  7. #define EX_NOHOST 68 /* host name unknown */
  8. #define EX_UNAVAILABLE 69 /* service unavailable */
  9. #define EX_SOFTWARE 70 /* internal software error */
  10. #define EX_OSERR 71 /* system error (e.g., can‘t fork) */
  11. #define EX_OSFILE 72 /* critical OS file missing */
  12. #define EX_CANTCREAT 73 /* can‘t create (user) output file */
  13. #define EX_IOERR 74 /* input/output error */
  14. #define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */
  15. #define EX_PROTOCOL 76 /* remote error in protocol */
  16. #define EX_NOPERM 77 /* permission denied */
  17. #define EX_CONFIG 78 /* configuration error */
  18. #define EX__MAX 78 /* maximum listed value */

使用示例

示例一 退出當前shell

[root@new55 ~]#
[root@new55 ~]# exit
logout

示例二 在腳本中,進入腳本所在目錄,否則退出

Bash代碼 技術分享圖片
  1. cd $(dirname $0) || exit 1

示例三 在腳本中,判斷參數數量,不匹配就打印使用方式,退出

Bash代碼 技術分享圖片
  1. if [ "$#" -ne "2" ]; then
  2. echo "usage: $0 <area> <hours>"
  3. exit 2
  4. fi

示例四 在腳本中,退出時刪除臨時文件

Bash代碼 技術分享圖片
  1. trap "rm -f tmpfile; echo Bye." EXIT

示例五 檢查上一命令的退出碼

Bash代碼 技術分享圖片
  1. ./mycommand.sh
  2. EXCODE=$?
  3. if [ "$EXCODE" == "0" ]; then
  4. echo "O.K"
  5. fi

來源: http://codingstandards.iteye.com/blog/836625

表格 D-1. "保留的"退出碼

退出碼的值含義例子註釋
1 通用錯誤 let "var1 = 1/0" 各種各樣的錯誤都可能使用這個退出碼, 比如"除0錯誤"
2 shell內建命令使用錯誤(Bash文檔上有說明) 很少看到, 通常情況下退出碼都為1
126 命令調用不能執行 程序或命令的權限是不可執行的
127 "command not found" 估計是$PATH不對, 或者是拼寫錯誤
128 exit 的參數錯誤 exit 3.14159 exit只能以整數作為參數, 範圍是0 - 255(見腳註)
128+n 信號"n"的致命錯誤 kill -9 腳本的$PPID $? 返回137(128 + 9)
130 用Control-C來結束腳本 Control-C是信號2的致命錯誤, (130 = 128 + 2, 見上邊)
255* 超出範圍的退出狀態 exit -1 exit命令只能夠接受範圍是0 - 255的整數作為參數

通過上面的表, 我們了解到, 退出碼1 - 2, 126 - 165, 和255 [1] 都具有特殊的含義, 因此應該避免使用用戶指定的退出參數. 如果腳本使用exit 127作為退出語句, 那麽可能就會在故障診斷的時候產生混淆(如何判斷這是由"command not found"引起的, 還是由用戶定義引起的?). 然而, 許多腳本使用exit 1作為通用的返回錯誤值. 因為退出碼1能夠表示的錯誤太多了, 不過這麽做, 對於調試來說, 也起不到任何幫助的作用.

其實早就有人對退出狀態值進行了系統的分類(請參考/usr/include/sysexits.h), 不過這個文件是為C/C++程序員準備的. 其實shell腳本也需要這樣一個類似的標準. 所以本文作者呼籲限制使用用戶定義的退出碼, 尤其是範圍64 - 113(還有0, 表示成功), 這麽做, 就可以和C/C++標準保持一致. 這樣我們就有了50個可用的退出碼, 而且非常便於故障診斷.

本書中所有例子中的用戶定義退出碼都符合這個標準, 除了那些超出標準範圍的例子, 比如例子 9-2.

只有在Bash或sh提示符下, 當shell腳本退出後, 在命令行上使用$?才會得到與上表相一致的結果. 在某些情況下, 運行C-shell或者tcsh可能會給出不同的值.

註意事項

超出範圍的退出值可能會產生意想不到的退出碼. 如果退出值比255大, 那麽退出碼將會取256的模. 舉個例子, exit 3809的退出碼將是225(3809 % 256 = 225).
來源: http://www.cnblogs.com/osroot/archive/2010/01/11/1643947.html

在C/C++中,__FUNCTION__常量記錄當前函數的名稱。有時候,在日誌輸出的時候包含這些信息是非常有用的。而在Bash中,同樣有這樣一個常量FUNCNAME,但是有一點區別是,它是一個數組而非字符串,其中數組的第一個元素為當前函數的名稱。

可能初看有點難以理解,為什麽FUNCNAME要是一個數組呢?看看下面的例子,你就明白了。

#!/bin/bashfunction test_func(){
    echo "Current $FUNCNAME, \$FUNCNAME => (${FUNCNAME[@]})"
    another_func
    echo "Current $FUNCNAME, \$FUNCNAME => (${FUNCNAME[@]})"}function another_func(){
    echo "Current $FUNCNAME, \$FUNCNAME => (${FUNCNAME[@]})"}

echo "Out of function, \$FUNCNAME => (${FUNCNAME[@]})"
test_func
echo "Out of function, \$FUNCNAME => (${FUNCNAME[@]})"

執行後的結果為:

Out of function, $FUNCNAME => ()
Current test_func, $FUNCNAME => (test_func main)
Current another_func, $FUNCNAME => (another_func test_func main)
Current test_func, $FUNCNAME => (test_func main)
Out of function, $FUNCNAME => ()

所以,更加準確地說,FUNCNAME是一個數組,但是bash中會將它維護成類似一個堆棧的形式。

與FUNCNAME相似的另外一個比較有用的常量是BASH_SOURCE,同樣是一個數組,不過它的第一個元素是當前腳本的名稱。
這在source的時候非常有用,因為在被source的腳本中,$0是父腳本的名稱,而不是被source的腳本名稱。而BASH_SOURCE
就可以派上用場了。

# If the script is sourced by another scriptif [ -n "$BASH_SOURCE" -a "$BASH_SOURCE" != "$0" ]then
    do_something
else # Otherwise, run directly in the shell
    do_other
fi

唯一遺憾的是,這種做法會讓腳本失去一些可移植性,因為不是所有的shell都支持這些常量。


來源: http://kodango.com/get-function-name-in-bash

Linux Shell Bash 帶有特殊含義的退出碼