popen

本文介绍了如何利用popen函数创建子进程执行shell命令,并通过示例代码展示了如何列出当前目录下的所有.jpg文件并将其重命名为.png。文章还详细解释了popen与pclose函数的工作原理。
       #include <stdio.h>

       FILE *popen(const char *command, const char *type);

       int pclose(FILE *stream);


函数说明

  popen()函数通过创建一个管道,调用fork()产生一个子进程,执行一个shell以运行命令来开启一个进程。这个管道必须由pclose()函数关闭,而不是fclose()函数。pclose()函数关闭标准I/O流,等待命令执行结束,然后返回shell的终止状态。如果shell不能被执行,则pclose()返回的终止状态与shell已执行exit一样。

  type参数只能是读或者写中的一种,得到的返回值(标准I/O流)也具有和type相应的只读或只写类型。如果type是"r"则文件指针连接到command的标准输出;如果type是"w"则文件指针连接到command的标准输入。

  command参数是一个指向以NULL结束的shell命令字符串的指针。这行命令将被传到bin/sh并使用-c标志,shell将执行这个命令。

  popen()的返回值是个标准I/O流,必须由pclose来终止。前面提到这个流是单向的(只能用于读或写)。向这个流写内容相当于写入该命令的标准输入,命令的标准输出和调用popen()的进程相同;与之相反的,从流中读数据相当于读取命令的标准输出,命令的标准输入和调用popen()的进程相同。

返回值

  如果调用fork()或pipe()失败,或者不能分配内存将返回NULL,否则返回标准I/O流。popen()没有为内存分配失败设置errno值。如果调用fork()或pipe()时出现错误,errno被设为相应的错误类型。如果type参数不合法,errno将返回EINVAL。


/**********************************
*将目录下.jpg文件打印到屏幕上为.png
***********************************/
#include <stdio.h>
#include <string.h>

char buf[1024];
int main(void)
{
	FILE *pp = popen("ls", "r");

	while(fgets(buf, 1024, pp)){
		char *s;
		if( (s = strstr(buf, ".jpg")) ){
			*s = '\0';			//取出指针s的内容即:. 
			printf("%s.png\n", buf);
		}
	}
	pclose(pp);
	return 0;


}

/*$ ./a.out 
1.png
2.png
a.png
$ ls
1.jpg  2.jpg  a.jpg  a.out  popen_mv.c  pop_name2.c
*/<pre name="code" class="cpp">












/**********************************
*将目录下.jpg文件修改为.png
***********************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char buf[1024];
int main(void)
{
	FILE *pp = popen("ls", "r");

	while(fgets(buf, 1024, pp)){
		char *s;

		if( (s = strstr(buf, ".jpg")) ){
			char str_mv[1024] = "mv ";
			if(buf[strlen(buf) - 1] == '\n'){
				buf[strlen(buf) - 1] = '\0';
			}
			strcat(str_mv, buf);	//mv 1.jpg无空格 (以文件1.jpg为例)
			strcat(str_mv, " ");    //mv 1.jpg空格
			
			*s = '\0';		//取出指针s的内容即:. 
			strcat(buf, ".png");    //buf里为1.png
			strcat(str_mv, buf);	//mv 1.jpg 1.png
			printf("%s\n", str_mv);
			system(str_mv);
		}
	}
	pclose(pp);
	return 0;


}


/*$ ls
1.jpg  2.jpg  a.jpg  a.out
$ ./a.out 
mv 1.jpg 1.png
mv 2.jpg 2.png
mv a.jpg a.png
*/




### Python `Popen` 使用方法及示例 #### 创建子进程并与其交互 为了创建一个新的进程并与之通信,可以使用 `subprocess.Popen` 类。此类提供了灵活性来管理子进程的标准输入、标准输出以及错误流。 ```python from subprocess import Popen, PIPE # 启动一个外部命令并将stdout和stderr重定向到PIPE proc = Popen(['echo', 'Hello World'], stdout=PIPE, stderr=PIPE) # 获取命令执行后的返回结果 output, error = proc.communicate() print(f'Output: {output.decode()}') if error: print(f'Error: {error.decode()}') ``` 上述代码展示了如何启动一个简单的命令,并通过管道读取其输出[^2]。 #### 设置参数传递给构造器 当实例化 `Popen` 对象时,可以通过向构造函数提供不同的参数来自定义行为: - **args**: 要运行的命令及其参数列表或者字符串形式。 - **bufsize**: 缓冲区大小;默认情况下为0(无缓冲),可设置为1表示行缓存或负数代表全缓冲。 - **executable**: 可选字段用于指定要执行的实际文件路径,在某些平台上可能有用。 - **stdin**, **stdout**, 和 **stderr**: 控制子进程中这些流的行为,默认值通常就足够用了。 - **preexec_fn/pre creation flags/startupinfo/close_fds**: 平台特定选项,允许更细粒度控制新进程属性。 更多细节可以在官方文档中找到关于各个平台的支持情况说明。 #### 实际应用场景举例 假设有一个场景是要调用 Git 来获取当前分支名称: ```python import subprocess def get_current_git_branch(): try: process = subprocess.Popen( ['git', 'rev-parse', '--abbrev-ref', 'HEAD'], stdout=subprocess.PIPE, universal_newlines=True ) output = process.stdout.read().strip() exit_code = process.wait(timeout=5) if exit_code != 0: raise Exception('Failed to retrieve git branch.') return output except FileNotFoundError as e: raise Exception('Git not installed or repository does not exist.') from e branch_name = get_current_git_branch() print(branch_name) ``` 这段脚本演示了怎样安全地处理潜在异常,并且合理利用超时机制防止无限等待子进程完成。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值