服务端用system()执行shell命令获取执行结果(排除signal影响)

最近在工作中遇到在服务端程序中需要执行shell命令,并获取执行结果的问题。 由于在服务端程序中一般会设置忽略子进程的信号处理:signal(SIGCHLD, SIG_IGN);

所以如果直接使用system()执行,并获取返回值作为命令执行成功与否的判断,是不合理的,这样会经常返回-1,但是命令实际上已经成功执行了。

网上搜索了一下处理方法:

signal(SIGCHLD, SIG_DFL);

ret = system(...);

signal(SIGCHLD, SIG_IGN);

先设置为默认,执行完命令,再设置为SIG_IGN, 但是程序运行中,发现还是会返回-1,所以这种方法还是不合理的。 

后来,又试了下使用popen()来处理:

int ret = -1;

FILE* fp = popen(shell_cmd.c_str(), "r");
if (!fp) {
return -1;
}

int rc =  pclose(fp);
ret = WEXITSTATUS(rc);

获取WEXITSTATUS()的返回值,作为命令执行的结果。 测试过程中发现,命令实际执行成功了,但是返回的值却是255。因此,这种方法还是不可行的。

这个问题困扰了我很久,始终找不到正确的方法,后面用了一种方法,经过验证,能正确得到命令的执行结果,但是当需要执行很多命令的时候,发现程序的进程数一直增加,最终导致系统宕掉。下面先说下这种方法的实现。


创建一个pipe, 再fork(), 在子进程中设置信号处理signal(SIGCHLD, SIG_DFL), 然后执行system()获取返回值,把返回值通过pipe()返回给父进程。

int system_ex(std::string const& shell_cmd)
{
	int fd[2], retcode = 0;
	pid_t pid;

	int result = pipe(fd);
	if (result == -1) {
		return -1;
	}

	pid = fork();
	if (-1 == pid) {
		return -1;
	} else if (0 == pid) {
		signal(SIGCHLD, SIG_DFL);
		close(fd[0]);
		int ret = system(shell_cmd.c_str());
		//int ret = WEXITSTATUS(status);
		write(fd[1], &ret, sizeof(ret));
	} else {
		close(fd[1]);
		read(fd[0], &retcode, sizeof(retcode));	
	}
	return retcode;
}

使用上面的代码,会导致程序挂掉,试了很久,后来通过重新popen()的实现过程,终于解决了进程不断增加的问题。

int popen_ex(std::string const& shell_cmd)
{
	int ret = 0;
	int pid, status;
#ifdef SIGCHLD
	signal(SIGCHLD, SIG_DFL);
#endif
	switch (pid = vfork()) {
		case -1:
			return -1;
		case 0:
			execl("/bin/sh", "sh", "-c", shell_cmd.c_str(), NULL);
			_exit(127);
	}
	waitpid(pid, &status, 0);

	ret = WEXITSTATUS(status);
#ifdef SIGCHLD
	signal(SIGCHLD, SIG_IGN);
#endif

	return ret;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值