Linux 进程12-13(system与popen的应用区别)

一、system函数()

详情看《unix环境高级编程》,8.13system函数。
在程序中执行一个命令字符串很方便。例如,假定要将时间和日期放到一个文件中,则可使用6 . 9节中的函数实现这一点。调用time得到当前日历时间,接着调用localtime将日历时间变换为年、月、日、时、分、秒、周日形式,然后调用strftime对上面的结果进行格式化处理,最后将结果写到文件中。但是用下面的system函数则更容易做到这一点。
system(“date > file”);
ANSI C定义了system函数,但是其操作对系统的依赖性很强。
因为system不属于操作系统界面而是 shell界面,所以POSIX.1没有定义它,POSIX.2则正在对其进行标准化。下列说明与POSIX.2标准的草案11.2相一致。

#include <stdlib.h>
int system(const char *cmdstring);
Returns: (see below)

如果cmdstring是一个空指针,则仅当命令处理程序可用时, system返回非0值,这一特征可以决定在一个给定的操作系统上是否支持system函数。在UNIX中,system总是可用的。
因为system在其实现中调用了fork、exec和waitpid,因此有三种返回值:
(1) 如果fork失败或者waitpid返回除EINTR之外的出错,则system返回-1,而且errno中设置了错误类型。
(2) 如果exec失败(表示不能执行shell ),则其返回值如同shell执行了exit(127)一样。
(3) 否则所有三个函数( fork,exec和waitpid )都成功,并且system的返回值是shell的终止状态,其格式已在waitpid中说明。

code:demo27.c

CLC@Embed_Learn:~/LinuxLearn/PID$ cat demo27.c
#include <stdio.h>
#include <unistd.h>

/

int main()
{
	printf("NOW TIME:\n");
	char *argv[]={"data",NULL};
	if(system("date") == -1){
		printf("Not Find File\n");
		perror("ERROR Reason:");
	}
	printf("SEEK!!!\n");//调用system会继续执行,而exec族不会
	return 0;
}

CLC@Embed_Learn:~/LinuxLearn/PID$ gcc demo27.c
CLC@Embed_Learn:~/LinuxLearn/PID$ ./a.out
NOW TIME:
20210519日 星期三 20:13:04 CST
SEEK!!!

二、popen函数

函数名:
popen, pclose − 与进程之间的管道流
原型:

#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);

glibc的特性测试宏要求(参见feature_test_宏(7)):
popen(), pclose():
_POSIX_C_SOURCE >= 2 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE
DESCRIPTION描述

  • popen()函数通过创建管道、分叉和调用shell来打开进程。由于管道的定义是单向的,类型参数只能指定读或写,而不能同时指定读或写;相应的,产生的流是只读的或只写的。
  • command参数是一个指针,指向包含shell命令行的以空结束的字符串。这个命令使用−c标志传递到/bin/sh;如果有解释,则由shell执行。type参数是一个指向以空结束的字符串的指针,该字符串必须包含字母’r’(用于读取)或字母’w’(用于写入)。因为glibc 2.9,这个参数可以额外包含字母’e’,这导致在底层文件描述符上设置执行时关闭标志(FD_CLOEXEC);的描述O_CLOEXEC标志在开放(2)的原因,这可能是有用的。
  • popen()的返回值在各个方面都是一个正常的标准I/O流,除了它必须用pclose()而不是fclose(3)关闭。对这样一个流的写入写入命令的标准输入;该命令的标准输出与调用popen()的进程的输出相同,除非该命令本身改变了这一点。相反,从“popened”流读取命令的标准输出,并且命令的标准输入与调用popen()的进程的标准输入相同。
  • 注意输出popen()流在默认情况下是完全缓冲的。
  • pclose()函数等待相关进程终止,并返回wait4(2)返回的命令退出状态。

返回值:

  • 如果fork(2)或pipe(2)调用失败,或者不能分配内存,popen()函数返回NULL。
  • 如果wait4(2)返回错误,或者检测到其他错误,则pclose()函数返回−1。

错误

  • 如果内存分配失败,popen()函数不会设置errno。如果底层的fork(2)或pipe(2)失败,errno将被适当设置。如果类型参数无效,并且检测到此条件,errno将被设置为EINVAL。
  • 如果pclose()不能获得子状态,errno被设置为ecchild。

符合(兼容于)
posix . 1的授权- 2001。
type的’e’值是一个Linux扩展

BUGS

  • 由于打开用于读取的命令的标准输入与调用popen()的进程共享其seek偏移量,如果原始进程已经进行了缓冲读取,则命令的输入位置可能不像预期的那样。类似地,打开用于写入的命令的输出可能会与原始进程的输出混杂在一起。后者可以通过在popen()之前调用fflush(3)来避免
  • shell执行失败与shell执行命令失败或命令立即退出没有区别。唯一的提示是退出状态为127。

参考
sh(1), fork(2), pipe(2), wait4(2), fclose(3), fflush(3), fopen(3), stdio(3), system(3)

code:demo28.c

#include <stdio.h>
#include <unistd.h>
//       size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
//       FILE *popen(const char *command, const char *type);
int main()
{
        FILE *fp;
        char ret[1024] = {0};
        fp = popen("ps","r");
        int read_byt = fread(ret,1,1024,fp);
        printf("read %d byte,result:%s\n",read_byt,ret);

        return 0;
}

运行结果:

CLC@Embed_Learn:~/LinuxLearn/PID$ gcc demo28.c
CLC@Embed_Learn:~/LinuxLearn/PID$ ./a.out
read 171 byte,result: PID TTY TIME CMD
46666 pts/4 00:00:01 bash
48141 pts/4 00:00:00 a.out
49185 pts/4 00:00:00 a.out
49186 pts/4 00:00:00 sh
49187 pts/4 00:00:00 ps

CLC@Embed_Learn:~/LinuxLearn/PID$ cat demo29.c
#include <stdio.h>
#include <unistd.h>
//       size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
//       FILE *popen(const char *command, const char *type);
int main()
{
	FILE *fp;
	char ret[1024] = {0};
	fp = popen("ps","r");	
	int read_byt = fread(ret,1,1024,fp);
//	printf("read %d byte,result:%s\n",read_byt,ret);
	return 0;
}

CLC@Embed_Learn:~/LinuxLearn/PID$ gcc demo29.c
CLC@Embed_Learn:~/LinuxLearn/PID$ ./a.out
CLC@Embed_Learn:~/LinuxLearn/PID$

三、小结

  • system 通过调用exec族实现,直接暴力执行,调用成功不返回。
  • popen调用不打印,看demo29.c,存放在FILE *stread(流)中。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值