1. 程式人生 > >linux system函式返回值詳解(1)

linux system函式返回值詳解(1)

曾經的曾經,被system()函式折磨過,之所以這樣,是因為對system()函數了解不夠深入。只是簡單的知道用這個函式執行一個系統命令,這遠遠不夠,它的返回值、它所執行命令的返回值以及命令執行失敗原因如何定位,這才是重點。當初因為這個函式風險較多,故拋棄不用,改用其他的方法。這裡先不說我用了什麼方法,這裡必須要搞懂system()函式,因為還是有很多人用了system()函式,有時你不得不面對它。 先來看一下system()函式的簡單介紹:
1 #include <stdlib.h>
2 int system(const char *command);

system() executes a command specified in command by calling /bin/sh -c command, and returns after the command has been completed. During execution of the command, SIGCHLD will be blocked, and SIGINT and SIGQUIT will be ignored.

system()函式呼叫/bin/sh來執行引數指定的命令,/bin/sh 一般是一個軟連線,指向某個具體的shell,比如bash,-c選項是告訴shell從字串command中讀取命令; 在該command執行期間,SIGCHLD是被阻塞的,好比在說:hi,核心,這會不要給我送SIGCHLD訊號,等我忙完再說; 在該command執行期間,SIGINT和SIGQUIT是被忽略的,意思是程序收到這兩個訊號後沒有任何動作。 再來看一下system()函式返回值: The value returned is -1 on error (e.g. fork(2) failed), and the return status of the command otherwise. This latter return status is in the format specified in wait(2). Thus, the exit code of the command will be WEXITSTATUS(status). In case /bin/sh could not be executed, the exit status will be that of a command that does exit(127).
If the value of command is NULL, system() returns nonzero if the shell is available, and zero if not. 為了更好的理解system()函式返回值,需要了解其執行過程,實際上system()函式執行了三步操作: 1.fork一個子程序; 2.在子程序中呼叫exec函式去執行command; 3.在父程序中呼叫wait去等待子程序結束。 對於fork失敗,system()函式返回-1。 如果exec執行成功,也即command順利執行完畢,則返回command通過exit或return返回的值。 (注意,command順利執行不代表執行成功,比如command:"rm debuglog.txt",不管檔案存不存在該command都順利執行了) 如果exec執行失敗,也即command沒有順利執行,比如被訊號中斷,或者command命令根本不存在,system()函式返回127. 如果command為NULL,則system()函式返回非0值,一般為1. 看一下system()函式的原始碼
看完這些,我想肯定有人對system()函式返回值還是不清楚,看原始碼最清楚,下面給出一個system()函式的實現:
01 int system(const char * cmdstring)
02 {
03 pid_t pid;
04 int status;
05
06 if(cmdstring == NULL)
07 {
08 return (1); //如果cmdstring為空,返回非零值,一般為1
09 }
10
11 if((pid = fork())<0)
12 {
13 status = -1; //fork失敗,返回-1
14 }
15 else if(pid == 0)
16 {
17 execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
18 _exit(127); // exec執行失敗返回127,注意exec只在失敗時才返回現在的程序,成功的話現在的程序就不存在啦~~
19 }
20 else //父程序
21 {
22 while(waitpid(pid, &status, 0) < 0)
23 {
24 if(errno != EINTR)
25 {
26 status = -1; //如果waitpid被訊號中斷,則返回-1
27 break;
28 }
29 }
30 }
31
32 return status; //如果waitpid成功,則返回子程序的返回狀態
33 }
仔細看完這個system()函式的簡單實現,那麼該函式的返回值就清晰了吧,那麼什麼時候system()函式返回0呢?只在command命令返回0時。 看一下該怎麼監控system()函式執行狀態 這裡給我出的做法:
01 int status;
02 if(NULL == cmdstring) //如果cmdstring為空趁早閃退吧,儘管system()函式也能處理空指標
03 {
04 return XXX;
05 }
06 status = system(cmdstring);
07 if(status < 0)
08 {
09 printf("cmd: %s\t error: %s", cmdstring, strerror(errno)); // 這裡務必要把errno資訊輸出或記入Log
10 return XXX;
11 }
12
13 if(WIFEXITED(status))
14 {
15 printf("normal termination, exit status = %d\n", WEXITSTATUS(status)); //取得cmdstring執行結果
16 }
17 else if(WIFSIGNALED(status))
18 {
19 printf("abnormal termination,signal number =%d\n", WTERMSIG(status)); //如果cmdstring被訊號中斷,取得訊號值
20 }
21 else if(WIFSTOPPED(status))
22 {
23 printf("process stopped, signal number =%d\n", WSTOPSIG(status)); //如果cmdstring被訊號暫停執行,取得訊號值
24 }

system()函式用起來很容易出錯,返回值太多,而且返回值很容易跟command的返回值混淆。這裡推薦使用popen()函式替代,關於popen()函式的簡單使用也可以通過上面的連結檢視。

popen()函式較於system()函式的優勢在於使用簡單,popen()函式只返回兩個值:
成功返回子程序的status,使用WIFEXITED相關巨集就可以取得command的返回結果;
失敗返回-1,我們可以使用perro()函式或strerror()函式得到有用的錯誤資訊。

這篇文章只涉及了system()函式的簡單使用,還沒有談及SIGCHLD、SIGINT和SIGQUIT對system()函式的影響,事實上,之所以今天寫這篇文章,是因為專案中因有人使用了system()函式而造成了很嚴重的事故。現像是system()函式執行時會產生一個錯誤:“No child processes”。

2012-04-14 [email protected]

轉載請註明出處。

相關推薦

linux system函式返回1

曾經的曾經,被system()函式折磨過,之所以這樣,是因為對system()函數了解不夠深入。只是簡單的知道用這個函式執行一個系統命令,這遠遠不夠,它的返回值、它所執行命令的返回值以及命令執行失敗原因如何定位,這才是重點。當初因為這個函式風險較多,故拋棄不用,改用其他的方法。這裡先不說我用了什麼方法,這裡

Linuxsystem函式返回

描述 system()庫函式使用fork(2)建立一個子程序,該子程序使用execl(3)執行指定的shell命令, execl(“/bin/sh”, “sh”, “-c”, command

Linux system函式返回(linux C++呼叫shell)

階段2:呼叫/bin/sh拉起shell指令碼,如果拉起失敗或者shell未正常執行結束(參見備註1),原因值被寫入到status的低8~15位元位中。system的man中只說明瞭會寫了127這個值,但實測發現還會寫126等值。

Linux system函式返回

階段2:呼叫/bin/sh拉起shell指令碼,如果拉起失敗或者shell未正常執行結束(參見備註1),原因值被寫入到status的低8~15位元位中。system的man中只說明瞭會寫了127這個值,但實測發現還會寫126等值。

Linux system 函式返回

如何判斷階段2中,shell指令碼是否正常執行結束呢?系統提供了巨集:WIFEXITED(status)。如果WIFEXITED(status)為真,則說明正常結束。 如何取得階段3中的shell返回值?你可以直接通過右移8bit來實現,但安全的做法是使用系統提供的巨集:WEXITSTATUS(status

Linux的SOCKET編程

readv lose 服務 網絡字節序 返回值 quest avi 取數 key Linux的SOCKET編程詳解 1. 網絡中進程之間如何通信 進 程通信的概念最初來源於單機系統。由於每個進程都在自己的地址範圍內運行,為保證兩個相互通信的進 程之間既互不幹擾又

linux c/c++ GDB教程轉載

spec -h AS 不同的 argv 路徑 scheme execution ram 學習使用了GDB一段時間後,發現它真的好強大!好用! GDB是GNU開源組織發布的一個強大的UNIX下的程序調試工具。或許,各位比較喜歡那種圖形界面方式的,像VC、BCB等IDE的調試,

linux】Valgrind工具集十三:DRD執行緒錯誤檢測器

一、概述 多執行緒程式設計需要注意的問題: 資料競爭;鎖競爭;POSIX執行緒API使用不當;死鎖; 二、使用 1、例子main.c原始碼 #include <stdio.h> #include <pthread.h> #include <s

linux】Valgrind工具集十三:Helgrind執行緒錯誤檢測器

一、概述 Helgrind用於檢測C、C ++和Fortran程式中使用符合POSIX標準的執行緒函式造成的同步錯誤。 POSIX中關於執行緒的主要抽象描述有:共享公共地址空間的一組執行緒、執行緒建立、執行緒連線、執行緒退出、互斥(鎖)、條件變數(執行緒間事件通知)、讀寫器鎖、自

linux】Valgrind工具集:SGCheck檢查棧和全域性陣列溢位

一、概述 SGCheck是一種用於檢查棧中和全域性陣列溢位的工具。它的工作原理是使用一種啟發式方法,該方法源於對可能的堆疊形式和全域性陣列訪問的觀察。 棧中的資料:例如函式內宣告陣列int a[10],而不是malloc分配的,malloc分配的記憶體是在堆中。 SGCheck和Me

linux】Valgrind工具集:Memcheck檢查的內容和方法

一、值的有效性 1、什麼是值的有效性? 英文原文是Valid-value (V) bits,直譯過來就是有效值(V)位。 我將它理解為值的有效性,就是判斷在記憶體或CPU的實體地址中儲存的資料是否有效,比如在記憶體中變數(int i)代表的物理位置(不是地址),沒有初始化,就去使用它

linux】Valgrind工具集:Memcheck命令列引數

【linux】Valgrind工具集詳解(五):命令列詳解中不夠全,在此專門針對Memcheck工具中的命令列引數做一次詳細的解釋。 Memcheck命令列選項 –leak-check=<no|summary|yes|full> [default: summary]

linux】Valgrind工具集:Memcheck記憶體錯誤檢測器

一、概述 Memcheck是一個記憶體錯誤檢測器。它可以檢測C和C ++程式中常見的以下問題: 1、非法記憶體:如越界、釋放後繼續訪問; 2、使用未初始化的值; 3、釋放記憶體錯誤:如double-free(同一記憶體上執行了兩次free)、或者 malloc、new、new[] 與

linux】Valgrind工具集:使用Valgrind gdbserver和GDB除錯程式

一、概述 在Valgrind下執行的程式不是由CPU直接執行的。相反,它執行在Valgrind提供的合成CPU上。這就是偵錯程式在Valgrind上執行時無法除錯程式的原因。 二、快速入門 在使用Memcheck工具時使用GDB除錯程式,啟動方式如下: 1、valgrind

linux】Valgrind工具集:命令列

一、使用方法 usage: valgrind [options] prog-and-args 使用方法:valgrind [引數選項] 程式和引數 二、選擇工具 tool-selection option, with default in [ ]: 工具選擇選項,預設值在[]

linux中mariadb基本用法企業級

資料庫 表的每一個列名字的頭   叫做欄位 是高階的exel表格軟體 資料庫種類 sqlserver  sqllite  db2   oracle  > mysql   比較多   其中my

linux】Valgrind工具集:列印資訊說明

一、列印資訊格式 Valgrind列印資訊的格式如下,很容易和程式輸出資訊區分出來 == 程序ID ==Valgrind的列印資訊 二、列印到何處 1、列印到檔案描述符中 主要是設定列印到終端上,預設情況下為2(stderr標準錯誤輸出)。如果要想列印到其他檔

Linux下套接字---epoll模式下的IO多路複用伺服器

1 epoll模型簡介 epoll可是當前在Linux下開發大規模併發網路程式的熱門人選,epoll 在Linux2.6核心中正式引入,和select相似,其實都I/O多路複用技術而已,並沒有什麼神祕的。 其實在Linux下設計併發網路程式,向來不缺少

Linux下串列埠通訊開啟串列埠和串列埠初始化

linux下串列埠通訊主要有下面幾個步驟 串列埠通訊流程圖 下面我會一一介紹這幾個步驟。 1.開啟串列埠 程式碼(串列埠為ttyUSB0) //開啟串列埠 int open_port(void) { int fd; fd=open("/dev/ttyUSB0

linux下的Makefile1

七、清空目標檔案的規則 每個Makefile中都應該寫一個清空目標檔案(.o和執行檔案)的規則,這不僅便於重編譯,也很利於保持檔案的清潔。這是一個“修養”(呵呵,還記得我的《程式設計修養》嗎)。一般的風格都是: clean: rm edit $(objects) 更為穩健的做法是: .PHONY : clea