Linux系統編程之system函數

目錄

 

一、前言

二、函數簡介

三、實例程序

四、總結


一、前言

在程序中執行一個命令字符串很方便。例如,我們想把一個日期輸入到一個文件中,可能寫一個腳本。。。,但是現在我們可以直接使用

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 函數進行了所需的各種出錯處理以及信號處理。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章