linux程序设计——管道输出数据到popen(第十三章)

13.3    将输出送往popen

看过捕获外部程序输出的例子后,再来看一个将输出发送到外部程序的示例程序popen2.c,它将数据通过管道送到另一个程序.在这里使用的是od(八进制)命令.

编写程序popen2.c,它非常类似popen1.c,唯一的不同是这个程序将数据写入管道,而不是从管道中读取.

/*************************************************************************
 > File Name:    popen2.c
 > Description:  popen2.c程序将数据写入管道
 > Author:       Liubingbing
 > Created Time: 2015年07月09日 星期四 19时43分51秒
 > Other:        popen2.c程序的作用等同于在命令行上输入echo "Once upon a time, there was..." | od -c
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(){
	FILE *write_fp;
	char buffer[BUFSIZ + 1];

	/* 将字符串写入buffer */
	sprintf(buffer, "Once upon a time, there was...\n");

	/* 函数popen允许一个程序给另一个程序传输数据
	 * 第二个参数"w"表明调用程序可以用fwrite调用向被调用程序发送数据
	 * 即将文件流指针write_fp指向的数据作为命令"od -c"的标准输入 */
	write_fp = popen("od -c", "w");
	if (write_fp != NULL) {
		/* fwrite向一个文件写入数据块
		 * 即将buffer中的数据写入到write_fp指向的文件,写入strlen(buffer)个元素,每个元素的大小为sizeof(char)个字节 */
		fwrite(buffer, sizeof(char), strlen(buffer), write_fp);
		pclose(write_fp);
		exit(EXIT_SUCCESS);
	}
	exit(EXIT_FAILURE);
}

程序使用带有参数"w"的popen启动od -c命令,这样就可以向该命令发送数据了.然后它给od -c命令发送一个字符串,该命令接收并处理它,最后把处理结果打印到自己的标准输出上.

在命令行上,可以用下面的命令得到同样的输出结果:

$ echo "Once upon a time, there was..." | od -c

程序popen2.c的结果如下所示:

13.3.1    传递更多的数据

目前所使用的机制都只是将所有数据通过一次fread或fwrite调用来发送或接收.有时,可能希望以块方式发送数据,或者根本就不知道输出数据的长度.为了避免定义一个非常大的缓冲区,可以用多个fread或fwrite调用来将数据分为几部分处理.

编写程序popen3.c,通过管道读取所有数据

/*************************************************************************
 > File Name:    popen3.c
 > Description:  popen3.c程序通过管道读取大量数据
 > Author:       Liubingbing
 > Created Time: 2015年07月09日 星期四 20时34分37秒
 > Other:        popen3.c
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(){
	FILE *read_fp;
	char buffer[BUFSIZ + 1];
	int chars_read;

	memset(buffer, '\0', sizeof(buffer));
	/* popen函数访问"ps ax"命令给出的信息
	 * 第一个参数"ps ax"是要运行的程序名和相应的参数
	 * 第二个参数open_mode="r"说明被调用程序的输出可以被调用程序使用
	 * 返回值为FILE*文件流指针read_fp,利用read_fp可以读取"ps ax"的输出信息 */
	read_fp = popen("ps ax", "r");
	if (read_fp != NULL) {
		/* fread函数从文件流指针read_fp指向的文件流中读取数据
		 * 最多读取BUFSIZ个元素,每个元素sizeof(char)个字节
		 * buffer用于接收数据的内存地址
		 * 如果成功则返回实际读取的元素的个数 */
		chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);
		if (chars_read > 0) {
			buffer[chars_read - 1] = '\0';
			printf("Reading %d:-\n %s\n", BUFSIZ, buffer);
			chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);
		}
		/* pclose关闭与popen关联的文件流(read_fp指向的文件流) */
		pclose(read_fp);
		exit(EXIT_SUCCESS);
	}
	exit(EXIT_FAILURE);
}

在这个程序中,从被调用的进程ps ax中读取数据.该进程输出的数据有多少事先无法知道,所以必须对管道进行多次读取.

这个程序调用popen函数时使用了"r"参数,这与popen1.c程序做法一样.这次,它连续从文件流中读取数据,直到没有数据可读为止.注意,虽然ps命令的执行要花费一些时间,但linux会安排好进程间的调度,让两个程序在可以运行时继续运行.如果读进程popen3没有数据可读,它将被挂起直到有数据到达.如果写进程ps产生的数据超过了可用缓冲区的长度,它也会被挂起直到读进程读取了一些数据.

在本例中,可能不会看到Reading:-信息的第二次出现.如果BUFSIZ的值超过了ps命令输出的长度,这种情况就会发生.

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-09-28 22:43:13

linux程序设计——管道输出数据到popen(第十三章)的相关文章

linux程序设计——父进程和子进程(第十三章)

13.5    父进程和子进程 这节将介绍如何在子进程中运行一个与父进程完全不同的另外一个程序,而不是仅仅运行一个相同程序.使用exec调用来完成这一项工作.这里的一个难点是,通过exec调用的进程需要知道应该访问哪个文件描述符.在前面的例子中,因为子进程本身有file_pipes数据的一份副本(点击打开"fork复制进程映像"链接),所以这并不成为问题.但经过exec调用后,情况就不一样了,因为原来的进程已经被新的进程替换了.为解决这个问题,可以将文件描述符(实际上它只是一个数字)作

linux程序设计——进程和信号总结(第十一章)

11.4.2    信号集 头文件signal.h定义了类型sigset_t和用来处理信号集的函数.sigaction和其他函数.sigaction和其他函数将用这些信号集来修改进程在接收到信号时的行为. #include <signal.h> int sigaddset(sigset_t *set, int signo); int sigemptyset(sigset_t *set); int sigfillset(sigset_t *set); int sigdelset(sigset_t

linux程序设计——IPC状态命令(第十四章)

14.5    IPC状态命令 虽然X/Open规范并没有定义它们,但大多数linux系统都提供了一组命令,用于从命令行上访问IPC信息以及清理游离的IPC机制.它们是ipcs和ipcrm命令,这两个命令对于开发程序非常有用. IPC机制一个让人烦恼的问题是:编写错误的程序或者因为某些原因而执行失败的程序把它的IPC资源(如消息队列中的数据)遗留在系统中,并且这些资源在程序结束后很长时间仍然在系统中游荡.这将导致对程序的新调用执行失败,因为程序期望以一个干净的系统来启动,但事实上却发现一些遗留的

linux --stdin 管道输出

--stdin This option is used to indicate that passwd should read the new password from standard input, which can be a pipe. 这个选项用于从标准输入管道读入新的密码. 使用 echo 方式来重置Linux 系统用户密码: echo “新密码”|passwd --stdin 用户名 1 2 3 4 5 6 7 8 9 10 [[email protected] ~]# passw

go语言接收linux/unix管道的数据

管道的内容,位于os.Stdin里,可以像普通文件一个操作os.Stdin,即可获取管道传过来的内容. package main import ( "bufio" "fmt" "log" "os" ) func main() { fileInfo, _ := os.Stdin.Stat() if (fileInfo.Mode() & os.ModeNamedPipe) != os.ModeNamedPipe { log

[Linux应用]Linux应用程序输出数据重定向到文件中

转自:http://blog.chinaunix.net/uid-20680966-id-4698387.html 目的是要让程序的printf的打印能重定向到某个文本中,ctrl+c强制退出后查看文本,方便调试.运行方式:a. out程序正常运行是会打印一些字符的 a.out > 1.txt 2>&1 把stdout与stderr都重定向到1.txt文件中去,结果发现运行过程中1.txt一直为空,调试发现如果a.out正常结束退出1.txt数据就正常,ctrl+c强制退出程序则1.t

《Linux程序设计 第四版》之第四章的练习题

1.P128 一个获取日期 时间 格式化获取时间 日期 的程序. #include<stdio.h> #include<time.h> int main(int argc,char** argv) { struct tm* time1,*time_trans; //时间数据结构 time_t alt; char c_time[128]; char* result; char* result1=""; time(&alt); time1=localtime

linux程序设计——CD唱片应用程序(第七章)

7.4 CD唱片应用程序 这篇为第七章的CD唱片应用程序,代码在CD唱片应用程序代码下载.我们使用dbm数据库对数据存储,改进之前的CD唱片应用程序. 7.4.1 更新设计 虽然在文件中以逗号分隔变量来存储信息是一种在shell中很容易实现的方式,但是这样局限性很大,因为许多CD标题和曲目都包含逗号.可以通过使用dbm数据库来改进这种方法. 将CD资料分为标题和曲目两个部分,并用不同的文件来保存它们. 前面的实现存在一个问题,即将应用程序的数据访问部分和用户接口部分混在了一起,这与程序全实现在一

linux程序设计——线程的属性(第十二章)

12.6    线程的属性 在前面的所有程序示例中,都在程序退出之前用pthread_join对线程再次进行同步,如果想让线程向创建它的线程返回数据就需要这样做.但有时,也有这种情况,既不需要第二个线程向主线程返回信息,也不想让主线程等待它的结束. 假设在主线程继续为用户提供服务的同时创建了第二个线程,新线程的作用是将用户正在编辑的数据文件进行备份存储.备份工作结束后,第二个线程就可以直接终止了,它没有必要再回到主线程中. 可以创建这一类型的线程,它们被称为脱离线程(detached threa