導讀 | 曾經的曾經,被system()函數折磨過,之因此這樣,是由於對system()函數了解不夠深刻。這裏必需要搞懂system()函數,由於有時你不得不面對它。 |
#include int system(const char *command)
system()函數調用/bin/sh來執行參數指定的命令,/bin/sh 通常是一個軟鏈接,指向某個具體的shell,好比bash,-c選項是告訴shell從字符串command中讀取命令; 在該command執行期間,SIGCHLD是被阻塞的,比如在說:hi,內核,這會不要給我送SIGCHLD信號,等我忙完再說; 在該command執行期間,SIGINT和SIGQUIT是被忽略的,意思是進程收到這兩個信號後沒有任何動做。html
爲了更好的理解system()函數返回值,須要瞭解其執行過程,實際上system()函數執行了三步操做:linux
看完這些,我想確定有人對system()函數返回值仍是不清楚,看源碼最清楚,下面給出一個system()函數的實現:shell
int system(const char * cmdstring) { pid_t pid; int status; if(cmdstring == NULL) { return (1); //若是cmdstring爲空,返回非零值,通常爲1 } if((pid = fork())<0) { status = -1; //fork失敗,返回-1 } else if(pid == 0) { execl("/bin/sh", "sh", "-c", cmdstring, (char *)0); _exit(127); // exec執行失敗返回127,注意exec只在失敗時才返回如今的進程,成功的話如今的 進程就不存在啦~~ } else //父進程 { while(waitpid(pid, &status, 0) < 0) { if(errno != EINTR) { status = -1; //若是waitpid被信號中斷,則返回-1 break; } } } return status; //若是waitpid成功,則返回子進程的返回狀態 }
仔細看完這個system()函數的簡單實現,那麼該函數的返回值就清晰了吧,那麼何時system()函數返回0呢?只在command命令返回0時。bash
int status; if(NULL == cmdstring) //若是cmdstring爲空趁早閃退吧,儘管system()函數也能處理空指針 { return XXX; } status = system(cmdstring); if(status < 0) { printf("cmd: %s\t error: %s", cmdstring, strerror(errno)); // 這裏務必要把errno信息輸出或 記入Log return XXX; } if(WIFEXITED(status)) { printf("normal termination, exit status = %d\n", WEXITSTATUS(status)); //取得cmdstring執行結果 } else if(WIFSIGNALED(status)) { printf("abnormal termination,signal number =%d\n", WTERMSIG(status)); //若是cmdstring被信號中 斷,取得信號值 } else if(WIFSTOPPED(status)) { printf("process stopped, signal number =%d\n", WSTOPSIG(status)); //若是cmdstring被信號暫停執 行,取得信號值 }
system()函數用起來很容易出錯,返回值太多,並且返回值很容易跟command的返回值混淆。這裏推薦使用popen()函數替代,關於popen()函數的簡單使用能夠本身查下資料。函數
popen()函數較於system()函數的優點在於使用簡單,popen()函數只返回兩個值: 成功返回子進程的status,使用WIFEXITED相關宏就能夠取得command的返回結果; 失敗返回-1,咱們可使用perro()函數或strerror()函數獲得有用的錯誤信息。測試
這篇文章只涉及了system()函數的簡單使用,尚未談及SIGCHLD、SIGINT和SIGQUIT對system()函數的影響,事實上,之因此今天寫這篇文章,是由於項目中因有人使用了system()函數而形成了很嚴重的事故。現像是system()函數執行時會產生一個錯誤:「No child processes」。此時調用my_system()來執行system函數的功能(my_system函數中是使用popen()函數來實現的), 測試了一天,沒有再次出現程序忽然死掉的問題(修改前連續循環調用system()函數測試,每10次就會至少致使程序掛掉一次.連續不停頓的調用)。debug
本文地址:http://www.linuxprobe.com/linux-system-constructors.html指針