system函數
在一個程序中執行命令字符串很方便。例如,我們想把時間和日期放到一份文件中,先用time得到當前日曆時間,接着調用localtime將日曆轉換爲年、月、日、時、分、秒,然後調用strftime對上面結果進行格式化處理,最後將結果寫入到文件中。
但是我們如果用stystem函數呢?
直接system(“data>file”),顯然很方便。
system函數原型
#include<stdio.h>
int system(const char* command)
system調用了fork創建子進程,由子進程來調用/bin/sh -c來執行參數command命令,執行完後返回。在調用system()期間SIGCHLD 信號會被暫時擱置,SIGINT和SIGQUIT信號則會被忽略。
調用/bin/sh來執行參數指定的命令,/bin/sh 一般是一個軟連接,指向某個具體的shell。
實際上system執行過程中調用了三個函數:
1.調用fork創建子進程
2.子進程調用exec去執行command命令
3.父進程調用waitpid等待子進程退出
因爲system調用了fork,exec、waitpid函數,因此有多個返回值:
1.command爲空,返回0;
2.fork,exec,waitpid都執行成功,返回shell終止狀態;
3..如果fork失敗或者waitpid返回除EINTR之外的錯誤,則system返回-1,而且error中設置了錯誤類型值。
4.如果exec失敗(表示不能執行shell),則返回127(等同shell執行exit(127)
函數源碼:
int system(const char * command)
{
pid_t pid;
int status;
if(command == NULL)
{
return (1); //如果cmdstring爲空,返回非零值,一般爲1
}
if((pid = fork())<0)
{
status = -1; //fork失敗,返回-1
}
else if(pid == 0) //子進程
{
execl("/bin/sh", "sh", "-c", command, (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成功,則返回子進程的返回狀態
}
popen函數
popen通過創建管道的方式來啓動一個進程,並調用 shell. 因爲管道是被定義成單向的, 所以 type 參數只能定義成只讀或者只寫, 不能是兩者同時, 結果流也相應的是隻讀或者只寫.
popen函數原型
#include<stdio.h>
FILE *popen(const char* command,const char* type)
int pclose(FILE* stream);
command 參數是一個字符串指針, 指向的是一個以 null 結尾的字符串, 這個字符串包含一個 shell 命令. 這個命令被送到 /bin/sh 以 -c 參數執行, 即由 shell 來執行.
返回值:成功返回一個文件指針,失敗返回NULL。只能用 pclose() 函數來關閉。
popen()會建立管道連到子進程的標準輸出設備或標準輸入設備,然後返回一個文件指針。 隨後進程便可利用此文件指針來讀取子進程的輸出設備或是寫入到子進程的標準輸入設備中。
實例:
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char* argv[])
{
char buf[128];
FILE* fp = popen("ls -l","w");
if(fp == NULL)
{
perror("popen");
exit(1);
}
while(fgets(buf,sizeof(buf),fp))
{
printf("%s",buf);
}
pclose(fp);
return 0;
}
測試結果:
總結:
1.system,popen都可用來創建進程.
2.system相當於fork+exec+waitpid,而popen是通過管道來啓動進程.
3.system 在執行期間,調用進程會一直等待 shell 命令執行完成(waitpid),但是 popen 無需等待 shell 命令執行完成就返回了。可以理解爲,system爲串行執行,popen 爲並行執行。
4.popen 函數執行完畢後必須調用 pclose 來對所創建的子進程進行回收,否則會造成殭屍進程的情況。