zoukankan      html  css  js  c++  java
  • 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中的字符串长度,不含 ; -1: 失败;
     *@remark         
     *@version        V1.0.0
     *@note     	  buf中最多返回size-1个字符,字符串始终以结尾。
    */
    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!
    ");
            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
    ");
    		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!
    ", cmd_string);
    	}
    
    	fd = open(tmpfile, O_RDONLY);
    	if(fd < 0)
        {
    		printf("open %s failed!
    ", 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;
    }
    

      

  • 相关阅读:
    zsh(yum装包的时候,有时候会不行)
    an error occurred during the file system check错误的解决
    Linux使用tcpdump命令抓包保存pcap文件wireshark分析
    安装win7或win8系统时UEFI和Legacy模式的设置
    查看LINUX当前负载
    svn update 每更新一项就输出一行信息,使用首字符来报告执行的动作 这些字符的含义是:
    svn分支管理进行迭代开发
    Linux命令行下创建纳入版本控制下的新目录
    svn update -r m path 代码还原到某个版本(这样之前的log日志也就没了,也就是清空log日志)
    二进制日志BINARY LOG清理
  • 原文地址:https://www.cnblogs.com/bwbfight/p/10682722.html
Copyright © 2011-2022 走看看