【问题标题】:How would I be able to pipe multiple commands using this program? C++我如何能够使用这个程序来传递多个命令? C++
【发布时间】:2020-06-19 06:20:04
【问题描述】:

我发现这个https://stackoverflow.com/a/50160844/7872119 解决了我目前的任务。然而,这是我第一次在 C++ 中使用管道。所以我对这一切还比较陌生。我很好奇,如果我想改变这个程序来处理多个管道,我怎么能准确地计算有多少个管道?我知道 ptr 变量是一个令牌,但是命令在解析时不会执行吗?我如何能够在执行之前计算所有管道?我希望能够在最后执行这样的事情

cat text.txt | sort | tail -3 | grep thankyou

【问题讨论】:

  • 答案是“将输入正确解析为代表管道的对象”。对于初学者,您可以拆分 | 字符并将结果列表的每个元素视为管道中的命令。
  • 问题的标题+内容和问题中提供的参考似乎与C++有关,删除了C标签。

标签: c++ shell pipe


【解决方案1】:

这比一开始看起来要复杂一些。应该遵守一些规则:

  1. 管道字符不能单独跟在后面(否则它们会形成|| 运算符)。

  2. 记住转义。

2a。其中字符串是最邪恶的。

假设我们可以实现一个部分功能的版本

std::string command{"cat text.txt | sort | tail -3 | grep thankyou"};
std::size_t count{};
for(auto pos = command.find_first_of("|\\\"'"); pos != command.npos;
         pos = command.find_first_of("|\\\"'", pos + 1))
{
    switch(command[pos]) {
        // a pipe char not followed by a pipe char is actually what we're looking for
        case '|': if(pos < command.size() - 1 && command[pos + 1] == '|')
                  {
                      ++pos; // ||
                  }
                  else ++count; // a real pipe
                  break
        // a plain one-char escape
        case '\\': ++pos;
                   break;
        case '\'': // iirc, there's no escape chars in singly-quoted strings
                   // skip until next '
                   pos = command.find('\'', pos + 1);
                   break;
        default: // a doubly-quoted string
                 pos = find_closing(command, pos);
    }
}

find_closing 应该使用带引号的字符串,如果有的话。

std::string::size_type find_closing(std::string const &cmd, std::size_t pos) {
    for(auto nxt = cmd.find_first_of("\"\\", pos + 1); nxt != cmd.npos;
             nxt = cmd.find_first_of("\"\\", nxt + 2))
    {
        if(cmd[nxt] == '"') return nxt; // unescaped closing double quote
    }
    return cmd.npos;
}

可能需要一些调试。

这段代码不能处理非常复杂的情况,比如echo "$(echo 123 | sed 's/2/4/')"

【讨论】:

    【解决方案2】:

    假设您在std::string 中有这一行:

    using Command = std::vector<std::string>;
    using Pipeline = std::vector<Command>;
    
    Pipeline p;
    Command c;
    std::istringstream iss(line);
    while (true) {
      std::string token;
      iss >> token;
      if (iss.eof()) {
        // Nothing more to read. Push the last command to the pipeline, if any.
        if (!c.empty()) {
          p.push_back(c);
        }
        break;
      }
    
      if (token == '|') {
        // We saw a pipe. Push the current command to the pipeline and
        // start parsing a new one.
        p.push_back(c);
        c.clear();
      } else {
        // This is a regular part of a command
        c.push_back(token);
      }
    }
    

    最后,p 将具有以下形状:

    [
      ["cat", "text.txt"],
      ["sort"],
      ["tail", -3],
      ["grep", "thankyou"]
    ]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-30
      • 2015-12-28
      • 2014-09-11
      • 2017-10-28
      • 2011-02-12
      • 2011-08-03
      • 2012-06-02
      • 2013-03-20
      相关资源
      最近更新 更多