我试图在C中实现一个shell.我可以用一个简单的execvp()来执行简单的命令,但其中一个要求是管理这样的命令:"ls -l | head | tail -4"with a for '循环并且只有一个'pipe()'语句重定向stdin和stdout.几天后,我有点迷失了.
N =简单命令的数量(示例中为3:ls,head,tail)命令=带有命令的结构列表,如下所示:
commands[0].argv[0]: ls
commands[0].argv[1]: -l
commands[1].argv[0]: head
commands[2].argv[0]: tail
commands[2].argv[1]: -4
Run Code Online (Sandbox Code Playgroud)
所以,我做了for循环,并开始重定向stdin和stdout以便用管道连接所有命令,但是...我只是无能为力它为什么不起作用.
for (i=0; i < n; i++){
pipe(pipe);
if(fork()==0){ // CHILD
close(pipe[0]);
close(1);
dup(pipe[1]);
close(pipe[1]);
execvp(commands[i].argv[0], &commands[i].argv[0]);
perror("ERROR: ");
exit(-1);
}else{ // FATHER
close(pipe[1]);
close(0);
dup(pipe[0]);
close(pipe[0]);
}
}
Run Code Online (Sandbox Code Playgroud)
我想要创建的是一系列childed进程:
[ls -l] ---- pipe ----> [head] ---- pipe ----> [tail -4]
所有这些进程都有一个root(运行我的shell的进程)所以,第一个父亲也是shell进程的一个孩子,我已经有点筋疲力尽了,有人可以帮助我吗?
我甚至不确定孩子是否应该是执行命令的孩子.
多谢你们 !!
[编辑:首先阅读接受的答案.下面的长期调查源于时间测量中的微妙错误.
我经常需要处理包含高度冗余数据的超大(100GB +)文本/类CSV文件,这些文件实际上无法存储在未压缩的磁盘上.我非常依赖外部压缩器,如lz4和zstd,它们产生的stdout流接近1GB/s.
因此,我非常关心Unix shell管道的性能.但是大型shell脚本很难维护,因此我倾向于使用Python构建管道,将命令拼接在一起并仔细使用shlex.quote().
这个过程繁琐且容易出错,因此我想要一种"Pythonic"方式来实现同样的目的,在不卸载的情况下管理Python中的stdin/stdout文件描述符/bin/sh.但是,我从未找到过这样做的方法而不会大大牺牲性能.
Python 3的文档建议使用方法替换shell管道.我已经调整了这个例子来创建下面的测试脚本,它将3GB的数据输入到一个无用的中,它什么都不输出:communicate()subprocess.Popen/dev/zerogrep
#!/usr/bin/env python3
from shlex import quote
from subprocess import Popen, PIPE
from time import perf_counter
BYTE_COUNT = 3_000_000_000
UNQUOTED_HEAD_CMD = ["head", "-c", str(BYTE_COUNT), "/dev/zero"]
UNQUOTED_GREP_CMD = ["grep", "Arbitrary string which will not be found."]
QUOTED_SHELL_PIPELINE = " | ".join(
" ".join(quote(s) for s in cmd)
for cmd in [UNQUOTED_HEAD_CMD, UNQUOTED_GREP_CMD]
)
perf_counter()
proc = Popen(QUOTED_SHELL_PIPELINE, shell=True)
proc.wait()
print(f"Time to run using shell …Run Code Online (Sandbox Code Playgroud)