在本篇文章當中主要給大家介紹一個shell的小知識——狀態碼。這是當我們的程式退出的時候,子程序會將自己程式的退出碼傳遞給父程序,有時候我們可以利用這一操作做一些程序退出之後的事情,比如當程式執行失敗或者被某個訊號殺死我們就可以瞭解到,然後做出對應的措施。
上圖是一個zsh的截圖,當我們執行命令asdsad
之後,因為沒有這個命令,所以zsh(類似於bash的一種shell),輸出沒有找到這個命令,但是我們發現圖中箭頭➡️由綠色變成紅色,表示程式不是正常退出。現在有一個問題是,zsh是怎麼知道程式不是正常退出的呢?其實就可以根據子程序退出的狀態推斷。在文章的最後我們用C語言實現一下,看看如果在父程序接收子程序的退出的狀態。
我們在命令列當中可以通過命令 echo $?
檢視上一個程序退出時候的退出碼,這裡的上一個程序就是 ls 命令:
程式正常退出的時候退出碼等於0。
退出碼 | 含義 | 例子 | 解釋 |
---|---|---|---|
1 | 一般的錯誤 | 除以0 | 一般的除以0的錯誤,執行沒有許可權的操作 |
2 | shell 內部操作失敗 | 通常是shell操作時候的命令錯誤,文章後面有一個例子演示 | |
126 | 執行不能夠執行的檔案 | /dev/random | 許可權問題或者命令不能夠執行 |
127 | 命令沒有找到 | 非法或者不存在的命令 | 執行一個系統當中不存在的命令,可以通過設定PATH環境變數 |
128+n | 錯誤的訊號值 | Kill -9 PID | 殺死程序號為PID的程序,程序的退出碼等於 128 + 9 |
130 | ctrl+c 之後程序的返回值 | 和上一條一樣ctrl+c的訊號值等於2 | |
其他 | 退出碼s不在範圍之內 | exit(-1) | 如果退出碼n不在0-255之內,那麼程式退出之後的退出碼為n&255,並且取低8位元作為最終的結果 |
上面直接進入root使用者的目錄,因為沒有許可權,檢視程序的退出碼等於1。
a=1
if [ $a -eq 1 ]
then
echo hello world
比如對於上面的shell指令碼是有語法錯誤的正確的語法還需要在最後加上fi,現在我們執行上面的指令碼檢視結果:
當因為許可權問題或者命令不可以執行那麼程序的退出碼就是126:
我們可以使用kil -l
命令檢視 linux 作業系統當中訊號以及對應的數值:
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
當我們在命令列使用ctrl+c中斷程式的執行的時候,這個正在執行的程序就會接受到SIGINT訊號,根據上文這個訊號對應的數值為2,因此程式的退出碼等於130(128 + 2)。
下面是一個通過kill命令傳送對應的訊號的例子:
可以看到的程式的退出碼是符號我們的預期的。
不在範圍內(0-255)的退出碼,需要和 0xff 進行 & 操作,得到的結果作為無符號數作為最終的程式的退出碼!
在上面的例子當中退出碼256的二進位制表示 1_0000_0000 他和 255(二進位制表示為1111_1111)進行與操作得到的結果為1_0000_000,低8位元等於0000_0000,因此最終的退出碼等於0。
在上面的圖當中-1的二進位制表示等於1111_1111 因此最後得到的退出碼等於1111_1111 = 255。
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
int main() {
if(fork() == 0) {
_exit(1); // 子程序執行
} else {
// 父程序執行
int status;
wait(&status); // WEXITSTATUS 這個宏就是獲取子程序退出時候的退出碼
printf("status = %d\n", WEXITSTATUS(status));
}
return 0;
}
在上面的程式碼當中父程序執行的 wait 函數就是等待子程序的狀態變化,當子程序退出的時候 wait 函數會返回,同時將子程序一些狀態資訊儲存在 status 當中,然後我們就可以子程序傳遞給父程序最後的資訊啦。其中 WEXITSTATUS 這個宏就是獲取子程序退出時候的退出碼!對應的 python 實現如下圖所示:
import os
import sys
if __name__ == '__main__':
pid = os.fork()
if pid == 0:
sys.exit(-1)
else:
pid, status = os.wait()
print(os.WEXITSTATUS(status))
在本篇文章當中主要給大家介紹了一些常見的程式退出的狀態碼!並且給出一下例子幫助大家仔細理解,並且使用C語言和python語言實現獲取子程序退出時候的退出狀態碼。
以上就是本篇文章的所有內容了,我是LeHung,我們下期再見!!!更多精彩內容合集可存取專案:https://github.com/Chang-LeHung/CSCore
關注公眾號:一無是處的研究僧,瞭解更多計算機(Java、Python、計算機系統基礎、演演算法與資料結構)知識。