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特别适用于构造简单的过滤程序,它变换运行命令的输入或输出。

当命令希望构建自己的管道线时就是这种情形。
 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值