如何在 C++ 中实现 grep那么它可以与管道(标准输入等)一起使用吗?

发布于 2024-11-02 08:36:06 字数 502 浏览 2 评论 0原文

我想为我在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

二智少女 2024-11-09 08:36:06

您想查看已传递了多少个命令行参数。如果只有一个,那么您假设您使用的是标准输入而不是文件。

在 C++ 中,可以通过在函数中使用对 std::istream 的引用来抽象这一点。在调用该函数之前,您需要决定(并创建)一个 std::ifstream(如果合适),否则使用 std::cin

因此,您的函数变为:

int grep(string stringToMatch, std::istream& in) // just one file
{
   // search file for stringToMatch
   // print line containing stringToMatch
}

并且您可以使用条件(在 main 中使用 argcargv)来执行以下操作

grep(string, std::cin);

std::ifstream file(fileName.c_str());
grep(string, file);

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) a std::ifstream if appropriate, or use std::cin otherwise.

Thus your function becomes:

int grep(string stringToMatch, std::istream& in) // just one file
{
   // search file for stringToMatch
   // print line containing stringToMatch
}

And you can use a conditional (using argc and argv in main) to do either:

grep(string, std::cin);

or

std::ifstream file(fileName.c_str());
grep(string, file);
潦草背影 2024-11-09 08:36:06

阅读 UNIX 过滤器此处

Unix 过滤器在标准输入和标准输出上进行通信。即,在第二进程的标准输入上接收第一进程的标准输出。

标准输入和输出本质上是二进制/文本流

此方法可以链接。 shell 通常是管理该程序的一方
- 环境
- 进程的启动、监控和退出
- 互连

所以
0. 用户给出命令,例如 ls
1. shell 找到命令,创建一个新进程,连接来自终端的 stdin 和来自终端的 stdout,
2.等待程序执行
3. 使用子进程的结果设置环境

如果您说您在向量中有“ls”输出,那么恐怕您还没有真正接近以真正的方式编写 shell

如果您想做一个没有所有内容的 shell考虑到进程管理、管道、重定向等的特性,最有用的工具是 std::istream 和 std::ostream (或 Boost IOStreams 库)。

grep 的一个非常非常简单(真的非常愚蠢)的版本可能如下所示:

#include <iostream>
#include <string>

static bool is_match(const std::string& text, const std::string& pattern)
{
    // FIXME TODO use actual (posix?) regex, boost regex, regex++ or whatnot
    return std::string::npos != text.find(pattern);
}


int main(int argc, const char* argv[])
{
    switch(argc)
    {
        case 0: case 1:
            std::cerr << "specify the pattern" << std::endl;
            return 254;
        case 2:
            break;
        default:
            std::cerr << "not implemented" << std::endl;
            return 255;
    }
    const std::string pattern(argv[1]);

    std::string line;
    while (std::getline(std::cin, line))
    {
        if (is_match(line, argv[1]))
            std::cout << line << std::endl;
    }

    return 0;
}

存在更好的示例 例如此处,但从问题来看,我认为这是下一步的信息丰富的步骤;)

另请注意,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:

#include <iostream>
#include <string>

static bool is_match(const std::string& text, const std::string& pattern)
{
    // FIXME TODO use actual (posix?) regex, boost regex, regex++ or whatnot
    return std::string::npos != text.find(pattern);
}


int main(int argc, const char* argv[])
{
    switch(argc)
    {
        case 0: case 1:
            std::cerr << "specify the pattern" << std::endl;
            return 254;
        case 2:
            break;
        default:
            std::cerr << "not implemented" << std::endl;
            return 255;
    }
    const std::string pattern(argv[1]);

    std::string line;
    while (std::getline(std::cin, line))
    {
        if (is_match(line, argv[1]))
            std::cout << line << std::endl;
    }

    return 0;
}

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

还给你自由 2024-11-09 08:36:06

您的 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 from stdin.

喜你已久 2024-11-09 08:36:06

当命令以您发布的语法出现时,它应该从标准输入读取其输入。因此,您需要传递给函数的不是文件名字符串,而是文件的打开文件描述符或 FILE*,无论它是文件系统驻留文件还是标准输入。

例如:

FILE *f;

if (argc == 3)
  f = fopen(argv[2], "r");
else
  f = stdin;

grep(argv[1], f);

请注意,如果您执行“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:

FILE *f;

if (argc == 3)
  f = fopen(argv[2], "r");
else
  f = stdin;

grep(argv[1], f);

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.

Smile简单爱 2024-11-09 08:36:06

您可能想使用一些库,例如 Boost Regex< /a> 并计算在 shell 中输入的模式的结果。

对于管道,这是 shell 的一个功能,而不是 grep。您可以查看 Boost InterprocessBoost 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.

谷夏 2024-11-09 08:36:06

当用户设置第二个参数时重新打开stdin

int grep(string stringToMatch, FILE *fp_in);


int main(int argc, char **argv)
{
    if (argc == 2) {
        freopen(argv[2], "r", stdin);
    }
    ...

}

reopen stdin when user set second argument.

int grep(string stringToMatch, FILE *fp_in);


int main(int argc, char **argv)
{
    if (argc == 2) {
        freopen(argv[2], "r", stdin);
    }
    ...

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文