如何在 C++ 中实现 grep那么它可以与管道(标准输入等)一起使用吗?
我想为我在 Windows 中执行的 Shell 实现 grep (仅用于学习目的)。
我知道 grep 具有以下语法:
grep pattern files
所以我可以创建一个如下函数:
int grep(string stringToMatch, string fileName) // just one file
{
// search file for stringToMatch
// print line containing stringToMatch
}
我的困惑是,当我使用这样的管道时 grep 应该如何工作:
ls | grep someword
我实现了“ls”以将所有输出放入向量中并返回所以我想我的 grep 应该在向量中搜索结果。那么正确的 grep 函数应该是什么样的呢?我需要 2 个 grep 函数吗?
提前致谢。
I want to implement grep for a Shell I'm doing in Windows (just for learning purpose).
I know that grep has the following syntax:
grep pattern files
So I can make a function like:
int grep(string stringToMatch, string fileName) // just one file
{
// search file for stringToMatch
// print line containing stringToMatch
}
My confusion is, how does grep supposed to work when I use a pipe like this:
ls | grep someword
I implemented "ls" to put all the output in a vector and return that, so I guess then my grep should search the vector for the results. So how should the correct grep function look ? Do I need 2 grep functions ?
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您想查看已传递了多少个命令行参数。如果只有一个,那么您假设您使用的是标准输入而不是文件。
在 C++ 中,可以通过在函数中使用对 std::istream 的引用来抽象这一点。在调用该函数之前,您需要决定(并创建)一个
std::ifstream
(如果合适),否则使用std::cin
。因此,您的函数变为:
并且您可以使用条件(在
main
中使用argc
和argv
)来执行以下操作:
You want to see how many command line arguments you've been passed. If there is only one then you assume that you're using stdin instead of a file.
In C++ this can be abstracted by using a reference to a
std::istream
in your function. Before you call the function you decide (and create) astd::ifstream
if appropriate, or usestd::cin
otherwise.Thus your function becomes:
And you can use a conditional (using
argc
andargv
inmain
) to do either:or
阅读 UNIX 过滤器 或 此处
Unix 过滤器在标准输入和标准输出上进行通信。即,在第二进程的标准输入上接收第一进程的标准输出。
标准输入和输出本质上是二进制/文本流
此方法可以链接。 shell 通常是管理该程序的一方
- 环境
- 进程的启动、监控和退出
- 互连
所以
0. 用户给出命令,例如 ls
1. shell 找到命令,创建一个新进程,连接来自终端的 stdin 和来自终端的 stdout,
2.等待程序执行
3. 使用子进程的结果设置环境
如果您说您在向量中有“ls”输出,那么恐怕您还没有真正接近以真正的方式编写 shell
如果您想做一个没有所有内容的 shell考虑到进程管理、管道、重定向等的特性,最有用的工具是 std::istream 和 std::ostream (或 Boost IOStreams 库)。
grep 的一个非常非常简单(真的非常愚蠢)的版本可能如下所示:
存在更好的示例 例如此处,但从问题来看,我认为这是下一步的信息丰富的步骤;)
另请注意,Boost IOstreams 库似乎包含 对管道的内置支持
Read up on UNIX filters or here
Unix filters communicate on standard input and standard output. I.e. the standard output of the first process is received on the standard input of the second process.
Standard input and output are essentially binary/text streams
This method can be chained. The shell is typically the party that manages the
- environment
- start, monitoring and exit of processes
- the interconnections
So
0. a user gives a command,e.g. ls
1. the shell finds the command, creates a new process, connects stdin from the terminal and stdout from thte terminal,
2. waits for program execution
3. sets environment with the result of the subprocess
If you say you have 'ls' output in a vector, I'm afraid that you are not really close to programming a shell in the true fashion
If you wanted to do a shell without all the idiosyncrasies of process management, pipes, redirections and whatnot, the most useful vehicle would be std::istream and std::ostream (or Boost IOStreams library).
A very very simple (really very dumb) version of grep could look like this:
Better examples exist e.g. here but judging from the question I though this was the next informative step down the road ;)
Note also that Boost IOstreams library seems to contain built-in support for pipelines
您的 grep 函数应该适用于
FILE *
(或 C++ 等效项)。如果您收到作为参数传递的文件名,请打开该文件。如果没有,请从stdin
读取。Your grep function should work on a
FILE *
(or the C++ equivalent). If you get a filename passed as an argument, open that file. If not, read fromstdin
.当命令以您发布的语法出现时,它应该从标准输入读取其输入。因此,您需要传递给函数的不是文件名字符串,而是文件的打开文件描述符或 FILE*,无论它是文件系统驻留文件还是标准输入。
例如:
请注意,如果您执行“ls | grep bar foo”,grep 将忽略 ls 的输出并匹配文件“foo”中的“bar”。因此,上面的代码反映了(嵌入了很多缺陷,但并不完全,因为 grep 可以匹配多个文件)grep 的行为。
When a command appears in such a syntax like you posted, it is supposed to read its input from the standard input. So, what you need to pass to your function isn't a string of the file name, but a open file descriptor or FILE* to a file, being it an file system resident file or the standard input.
Something like:
Notice that if you do "ls | grep bar foo", grep will ignore the output of ls and will match "bar" in the file "foo". So, the above code reflects (with a lot of flaws embedded, and not fully, as grep can match multiple files) the behavior of grep.
您可能想使用一些库,例如 Boost Regex< /a> 并计算在 shell 中输入的模式的结果。
对于管道,这是 shell 的一个功能,而不是 grep。您可以查看 Boost Interprocess 和 Boost Asio 库来实现它。 Boost Asio 支持许多 POSIX 进程间通信机制。
You might want to use some library like Boost Regex and compute the result of the pattern entered in your shell.
In the case of pipe, thats a feature of the shell and not grep. You can checkout Boost Interprocess and Boost Asio libraries to implement it. Boost Asio supports many POSIX interprocess communication mechanisms.
当用户设置第二个参数时重新打开stdin。
reopen stdin when user set second argument.