Search code examples
c++pipeuser-inputstdin

Redirect two separate stdin as input to a program


The following example outputs the input that comes from stdin:

#include <iostream>

int main(int argc, char **argv)
{
    std::string s1, s2;
    while (getline(std::cin, s1))
    {
        std::cout << s1 << " 1\n";
    }

    while (getline(std::cin, s2))
    {
        std::cout << s2 << "2\n";
    }
    return 0;
}

I run the program like this: cat main.cpp | ./main which outputs

#include <iostream> 1
 1
int main(int argc, char **argv) 1
{ 1
 1
    std::string s1, s2; 1
    while (getline(std::cin, s1)) 1
    { 1
        std::cout << s1 << " 1\n"; 1
    } 1
         1
    while (getline(std::cin, s2)) 1
    { 1
        std::cout << s2 << "2\n"; 1
    } 1
} 1

Is there a way to pipe two separate inputs to a program through stdin? I.e., so if I write something like cat main.cpp cat main.cpp | ./main, then the first input gets assigned to s1 and the second to s2?


Solution

  • AFAIK this is not possible, but you can simply use two files containing your input, pass them as a command line argument and read from them.

    #include <iostream>
    #include <fstream>
    
    int main(int argc, char **argv)
    {
        if (argc != 3) 
          return -1;
    
        std::ifstream ifs1(argv[1]);
        std::ifstream ifs2(argv[2]);
    
        if (!ifs1.is_open() || !ifs2.is_open())
          return -2;
    
        std::string s1, s2;
        while (getline(ifs1, s1))
        {
          std::cout << s1 << " 1\n";
        }
    
        while (getline(ifs2, s2))
        {
          std::cout << s2 << "2\n";
        }
        return 0;
    }
    

    And call it like this:

    ./main main.cpp main.cpp
    

    You can even make this more flexible, allowing you to read as many files as you wish:

    #include <iostream>
    #include <fstream>
    
    int main(int argc, char **argv)
    {
        if (argc == 1) 
          return -1; // no input file given
    
        for (int i = 1; i < argc; ++i) { 
          std::ifstream ifs(argv[i]);
    
          if (!ifs.is_open()) {
            std::cout << argv[i] << ":file not found\n";
            continue;
          }
    
          std::string line;
          while (getline(ifs, line))
          {
            std::cout << line << " " << i << "\n";
          }
        }
    }