Starting a process with string inputs and outputs

There are many questions related to fork () and exec (). I did not find one that really makes the process of using them simple, although it makes the life of a programmer a simple task.

I need C ++, a Linux-friendly function that does the following:

string RunCommand(string command, string input){} 

This function should be able to run a shell command, such as grep, and “connect” the input contents to it and read the message and return it. Therefore, if I do the following on the command line:

 ps -elf | grep somequerytext 

I would do the code:

 string psOutput = RunCommand("ps -elf",""); string grepOutput = RunCommand("grep somequerytext", psOutput); 

* edit: The question is what is the best implementation of the RunCommand function.

* edit: popen was considered a solution for simplicity, but popen limits you to sending data or outputting data, but not both.

+4
source share
3 answers

It seems you need a function:

  • Create two pipes and a plug.
  • Then the child process is executed:
    • Duplicate the corresponding pipe descriptors so that one file descriptor is standard input and one standard output
    • Close Channel Descriptors
    • Break command line into arguments
    • Run the command with arguments
  • Then the parent (main) process is executed:
    • Close the corresponding pipe file descriptors
    • Writes the input string to the child and closes the channel to standard input for children
    • Reads an output string from a child
    • Closes a tube from a standard output file
    • Expects the baby to die.
  • When the child is dead, the main process can continue, returning the line that it is reading.

The only potential problem with this circuit is that the child writes the output before it finishes reading its input, and it writes so much output that the channel is full (they have a finite and usually fairly small capacity). In this case, the processes will be slowed down - the parent tries to write to the child, and the child tries to write to the parents, and both are stuck, waiting for the other to read some data. You can avoid this if there are two threads in the parent, one handles the write and the other handles the read. Or you can use two child processes: one to run the command and one to write to standard input, while the parent reads from the standard output of the command to a string.

One reason a standard function does not exist is how difficult it is to decide what the corresponding semantics are.

I ignored the problems of error handling and signal processing; they add to the complexity of it all.

+4
source

Before discussing the implementation of RunCommand , consider this piece of code:

 string psOutput = RunCommand("ps -elf",""); string grepOutput = RunCommand("grep somequerytext", psOutput); 

In the above code snippet, the problem is that the commands are run sequentially and not run in parallel / parallel. (See Programming with POSIX Streams p. 9 ) For an example, if ps -elf generates a huge amount of data that will be stored in psOutput and then passed to the next command. But in a real implementation, each process in a pipe starts at the same time, and the data is transmitted using pipe (with some buffering, of course), and there is no need to wait for one process to complete before another process starts.

I suggest you study Richard Stephen’s Advanced Programming in the Unix Environment chapter. "Process Control" p. 223 to implement the system . Based on Richard Steven's code, a sample RunCommand implementation will look like this (skeletal code only, without error checking):

 int RunCommand(string command) { pit_t pid; if ( ( pid = fork() ) < 0 ) return -1; else if (pid == 0) { execl("/bin/sh", "sh", "-c", command.c_str(), (char*) 0); } else { /* The parent waits for the child */ wait(pid, ...); } } 

and then the following functions are called:

 string s("ps -elf | grep somequerytext"); int status = RunCommand(s); 

The shell will take care of parsing its input and running commands by installing a pipe between them. If you're interested in understanding how the shell works, see the “Minishell Example” in Terrence Chan Unix system programming using C ++ chap.8 “Unix Processes” (Jonathan Leffler answer pretty much describes the shell implementation!)

+4
source

Why not use popen() ? It is in the standard library and very easy to use:

 FILE* f = popen("ps -elf | grep somequerytext", "r"); char buf[2048]; buf[fread(buf, 1, 2048, f)] = '\0'; cout << buf; 
0
source

Source: https://habr.com/ru/post/1369350/


All Articles