linux執行命令並獲取結果(system)


執行系統命令,並返回輸出的結果

首先需要了解mkstemp():

mkstemp()函數在系統中以唯一的文件名創建一個文件並打開,而且只有當前用戶才能訪問這個 臨時文件,並進行讀、寫操作。
  mkstemp函數在系統中以唯一的文件名創建一個文件並打開,而且只有當前用戶才能訪問這個 臨時文件,並進行讀、寫操作。 mkstemp函數只有一個參數,這個參數是個以“XXXXXX”結尾的非 空字符串。mkstemp函數會用隨機產生的字符串替換“XXXXXX”,保證 了文件名的唯一性。 函數返回一個 文件描述符,如果執行失敗返回-1。
  在glibc 2.0.6 以及更早的 glibc庫中這個文件的訪問權限是0666,glibc 2.0.7以后的庫這個文件的訪問權限是0600。
  臨時文件使用完成后應及時刪除,否則臨時文件目錄會塞滿垃圾。由於mkstemp函數創建的 臨時文件不能自動刪除,所以執行完 mkstemp函數后要調用 unlink函數,unlink函數刪除文件的目錄入口,但臨時文件還可以通過文件描述符進行訪問,直到最后一個打開的進程關 閉文件 操作符,或者程序退出后臨時文件被自動徹底地刪除。
 
函數功能表示:讀取命令執行結果,放到臨時文件,並將結果讀到buf中,刪除臨時文件
 
/**
 *@brief          執行系統命令,並返回輸出的結果
 *@param[in]      cmdstring,命令串
 *@param[in]      buf,存放命令結果的緩沖區
 *@param[in]      size,緩沖區的大小
 *@param[out]     
 *@return         返回寫入到buf中的字符串長度,不含\0 ; -1: 失敗;
 *@remark         
 *@version        V1.0.0
 *@note     	  buf中最多返回size-1個字符,字符串始終以\0結尾。
*/
int get_cmd_results(const char *cmdstring, char *buff, int size)
{
	char cmd_string[200] = {0};
	char tmpfile[100] = {0};
	char tmp_buf[100] = {0};
	int fd;
	int tmp_fd;
	int nbytes;

      memset(buff, 0, size);

	if((cmdstring == NULL) ||
		(strlen(cmdstring) > (sizeof(tmpfile) + 8)) ||
		((strlen(cmdstring) + strlen(tmpfile) + 5) > sizeof(cmd_string)))
	{
        printf("cmd is too long or NULL!\n");
        return -1;
	}
	sscanf(cmdstring, "%[a-Z]", tmp_buf);/*%[a-z] 表示匹配a到z中任意字符,貪婪性(盡可能多的匹配) */
	sprintf(tmpfile, "/tmp/%s-XXXXXX", tmp_buf);

	tmp_fd = mkstemp(tmpfile);
	if(tmp_fd < 0)
    {
		printf("mkstemp failed\n");
		return -1;
	}
	close(tmp_fd);

	sprintf(cmd_string, "%s > %s 2>&1", cmdstring, tmpfile);/*標准輸出(1),標准錯誤(2)都輸出到臨時文件*/
	if(system_ex(cmd_string, 20) < 0)
    {
		printf("run \"%s\" ret < 0!\n", cmd_string);
	}

	fd = open(tmpfile, O_RDONLY);
	if(fd < 0)
    {
		printf("open %s failed!\n", tmpfile);
		nbytes = -1;
	}
	else
	{
		nbytes = read(fd, buff, size - 1);
		close(fd);
	}

	memset(cmd_string, 0, sizeof(cmd_string));
	sprintf(cmd_string, "rm -rf /tmp/%s-*", tmp_buf);
	system_ex(cmd_string, 20);

	return nbytes;
}

  system_ex:

首先請了解信號:signal和sigaction

https://blog.csdn.net/weibo1230123/article/details/81411827

https://www.cnblogs.com/lidabo/p/4581065.html

創建子進程執行命令,父進程忽略ignore SIGINT and SIGQUIT ,來避免影響子進程執行即需要子進程執行完畢,子進程不忽略信號,當超時或者子進程退出

則恢復信號狀態,超時的話,還需要kill掉子進程等

//system函數擴展,加入超時值(0表示永久等待)
//超時時返回-2,其他情況返回不變。
int system_ex(const char *cmdstring, unsigned int timeout)   /* with appropriate signal handling */
{
	pid_t               pid;
	int                 status;
	struct sigaction    ignore, saveintr, savequit;
	sigset_t            chldmask, savemask;

	//精度換成十分之一秒
	timeout *= 10;
	if (timeout == 0)
		timeout = 0xFFFFFFFF;

	if (cmdstring == NULL)
		return(1);      /* always a command processor with UNIX */

	ignore.sa_handler = SIG_IGN;    /* ignore SIGINT and SIGQUIT */
	sigemptyset(&ignore.sa_mask);
	ignore.sa_flags = 0;
	if (sigaction(SIGINT, &ignore, &saveintr) < 0)
		return(-1);
	if (sigaction(SIGQUIT, &ignore, &savequit) < 0)
		return(-1);
	sigemptyset(&chldmask);         /* now block SIGCHLD */
	sigaddset(&chldmask, SIGCHLD);
	if (sigprocmask(SIG_BLOCK, &chldmask, &savemask) < 0)
		return(-1);

	if ((pid = fork()) < 0) {
		return -1;    /* probably out of processes */
	} else if (pid == 0) {          /* child */
		/* restore previous signal actions & reset signal mask */
		sigaction(SIGINT, &saveintr, NULL);
		sigaction(SIGQUIT, &savequit, NULL);
		sigprocmask(SIG_SETMASK, &savemask, NULL);
/*通常exec會放在fork() 函數的子進程部分, 來替代子進程執行啦, 執行成功后子程序就會消失,  但是執行失敗的話, 必須用exit()函數來讓子進程退出!*/
		execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);/*exec函數會取代執行它的進程,  也就是說, 一旦exec函數執行成功, 它就不會返回了, 進程結束.   但是如果exec函數執行失敗, 它會返回失敗的信息,  而且進程繼續執行后面的代碼!*/
		_exit(127);     /* exec error */
	}

	/* parent */
	int ret = 0;
	while (timeout-- > 0 &&
		(ret = waitpid(pid, &status, WNOHANG)) == 0)
		usleep(100*1000);

	/* restore previous signal actions & reset signal mask */
	if (sigaction(SIGINT, &saveintr, NULL) < 0)
		return(-1);
	if (sigaction(SIGQUIT, &savequit, NULL) < 0)
		return(-1);
	if (sigprocmask(SIG_SETMASK, &savemask, NULL) < 0)
		return(-1);

	if (ret < 0)
		return -1;

	if (ret > 0)
		return status;

	kill(pid, SIGKILL);
	waitpid(pid, &status, 0);
	return -2;
}

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM