Linux中的popen函式和system函式
說在前面:在實際程式設計中儘量減少使用system函式。
int system(const char *command);
說明: system()通過呼叫/ bin / sh -c命令執行命令中指定的命令,並在命令完成後返回。在執行該命令期間,SIGCHLD將被阻塞,並且SIGINT和SIGQUIT將被忽略。
返回值:
實際上system呼叫了三個函式:fork()、exec()、waitpid()。因此有三種返回值:
1>fork()失敗或者waitpid()返回除了EINTR之外的出錯,則system返回-1.而且errno
中設定了錯誤型別值。
2>如果exec失敗(表示不能執行shell),則其返回值如同shell執行了exit(127)一樣
3>如果三個函式都執行成功,並且system的返回值是shell的終止狀態,其格式已在已在waitpid中說明。
system的實現:
int system(const char * cmdstring) { pid_t pid; int status; if(cmdstring == NULL) { return (1); } if((pid = fork())<0) { status = -1; } else if(pid = 0) { execl("/bin/sh", "sh", "-c", cmdstring, (char *)0); -exit(127); //子程序正常執行則不會執行此語句 } else { while(waitpid(pid, &status, 0) < 0) { if(errno != EINTER){ status = -1; break; } } } return status; }
簡單的使用:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> int main() { int status = 0; status = system("ls -a"); if(-1 == status) { perror("system"); exit(1); } if(WIFEXITED(status) != 0) //正常退出 { if(WEXITSTATUS(status) == 0) //操作正確 { printf("run command success\n"); } else { printf("run error\n"); } } else //異常退出 { printf("exit error is %d\n", WEXITSTATUS(status)); } return 0; }
通過上面的程式碼我們可以看到,system在使用時的一個弊端,由於返回值太多,要安全的使用它就要進行許多步的出錯處理。
所以,不太建議使用system。
使用system需要注意:
1、建議system()函式只用來執行shell命令,因為一般來講,system()返回值不是0就說明出錯了; 2、監控一下system()函式的執行完畢後的errno值,爭取出錯時給出更多有用資訊;建議使用popen函式取代system();
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);返回值: command的終止狀態, 出錯返回-1
popen()函式較於system()函式的優勢在於使用簡單,popen()函式只返回兩個值:
成功返回子程序的status,使用WIFEXITED相關巨集就可以取得command的返回結果;
失敗返回-1,我們可以使用perro()函式或strerror()函式得到有用的錯誤資訊。
popen先執行fork,然後呼叫exec以執行command並返回一個標準I/O檔案指標。如果type是“r”,則檔案指標連結到command的標準輸出。如果type是“w”,則檔案指標連結到command的標準輸入。將popen和fopen進行類比,方便記憶其最後一個引數及其作用,如果type是“r”,則返回檔案指標是刻度的,如果type是是“w”,則是可寫的。
簡單使用:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE* fp = NULL;
char buf[1024] = {0};
fp = popen("ls -a", "r");
if(NULL == fp)
{
perror("popen");
exit(1);
}
while(fgets(buf, 1024, fp) != NULL)
{
fprintf(stdout, "%s", buf);
}
pclose(fp);
return 0;
}
注意,popen絕不應該由設定使用者ID或設定組ID程式呼叫。當它執行命令
popen等同於execl("/bin/sh", "sh", "-c", command
,NULL);
它在從呼叫者繼承的環境中執行shell,並由shell解釋執行command。一個心懷不軌的使用者可以
操縱這種環境,使得shell能以設定ID檔案模式所授予的提升了
的許可權以及非預期的方式執行命令。
popen特別適用於構造簡單的過濾程式,它變換執行命令的輸入或輸出。
當命令希望構建自己的管道線時就是這種情形。