目錄
一、前言
在程序中執行一個命令字符串很方便。例如,我們想把一個日期輸入到一個文件中,可能寫一個腳本。。。,但是現在我們可以直接使用
system("date > time.file");
非常方便。
二、函數簡介
1、函數原型
#include<stdlib.h>
int system(const char *command);
2、函數功能
system() 庫函數使用 fork() 創建一個子進程,通過使用 execl 函數來執行 command 指定的 shell 命令。
execl("/bin/sh", "sh", "-c", command, (char *) 0);
調用 system() 函數在 command 命令被執行期間,SIGCHLD 信號將會被阻塞,SIGINT 和 SIGQUIT 信號將會被忽略。
如果 command 爲 NULL,那麼 system() 將會返回一個狀態,用來指示在這個系統中 shell 是否是可用的。
3、函數返回值
1> 如果 command 命令爲 NULL,如果 shell 是可用的返回非 0 ,或者 shell 不可用返回 0 ;
2> 如果如果子進程不能被創建,或者它的狀態不能夠被返回,那麼返回值爲 -1;
3> 如果 shell 在子進程中不能夠被執行,返回值與子 shell 一樣通過調用狀態爲 127 的_exit 來終止。
4> 如果所有系統調用成功,那麼這個返回值爲執行 command 的子 shell 的返回狀態。(shell的終止狀態是最後一個命令的終止狀態執行。)
三、實例程序
1、system.c (不帶任何信號處理的)
#include<stdio.h>
#include<signal.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<errno.h>
/*不處理任何的信號 */
int mysystem(char *command)
{
pid_t pid;
int status;
if(NULL == command)
return -1;
if((pid = fork()) < 0)
printf("創建子進程失敗\n");
else if(0 == pid)
{
/* shell 中 -c 選項告訴shell,讀取下一個命令行參數(這裏是 command )
作爲命令輸入(而不是從標準輸入或者一個給定的文件中讀取命令)
shell對以null字節終止的命令字符串進行語法分析,將它們分析成命令行參數*/
execl("/bin/sh", "sh", "-c", command, (char *)0);
/* exec 失敗(如果 shell 不能執行 ) 則返回值如同 shell 執行了 exit(127)一樣
注意:
在這裏使用的是_exit而不是exit,這是爲了防止任意標準IO(這些緩衝會在fork中
由父進程複製到子進程)在子進程中被沖洗*/
_exit(127);
}
else
{
/*父進程:等待子進程結束,如果失敗判斷錯誤類型 */
while(waitpid(pid, NULL, 0) < 0)
{
if(errno != EINTR)
status = -1;
break; /* 跳出循環 */
}
}
return 0;
}
2、pr_exit.c(退出狀態處理函數)
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
void pr_exit(int status)
{
if(WIFEXITED(status))
printf("正常結束,退出狀態 status = %d\n", WEXITSTATUS(status));
else if(WIFSIGNALED(status))
printf("異常結束,退出狀態 status = %d %s\n", WTERMSIG(status),
#ifdef WCOREDUMP
WCOREDUMP(status)?"內核文件被生成":"");
#else
"");
#endif
else if(WIFSTOPPED(status))
printf("子進程被終止,信號編號 number = %d\n", WSTOPSIG(status));
}
3、main.c 主函數
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<error.h>
extern int mysystem(char *command);
extern void pr_exit(int status);
int main(void)
{
int status;
if((status = mysystem("date")) < 0)
printf("system error");
pr_exit(status);
if((status = mysystem("nosuchcommand")) < 0)
printf("system error");
pr_exit(status);
if((status = mysystem("who;exit 44")) < 0)
printf("system error");
pr_exit(status);
return 0;
}
4、Makefile
all:
gcc main.c system.c pr_exit.c -o main
clean:
rm *.o
5、運行程序
gfy@gfy:/mnt/hgfs/SHARE/share/system$ ./main
2020年 03月 01日 星期日 20:08:39 CST
正常結束,退出狀態 status = 0
sh: 1: nosuchcommand: not found
正常結束,退出狀態 status = 0
gfy tty7 2020-02-28 09:40 (:0)
gfy pts/20 2020-03-01 16:23 (192.168.111.1)
正常結束,退出狀態 status = 0
四、總結
使用 system 函數而不直接使用 fork 和 exec 的優點:system 函數進行了所需的各種出錯處理以及信號處理。