The standard I/O function library provides the popen function, which starts another process to execute a shell command line.
Here we call the process that calls popen as the parent process, and the process started by popen as the child process.
The popen function also creates an MPS queue for parent-child process communication. The parent process either reads information from the MPs queue or writes information to the MPs queue. Whether the read or write operation is performed depends on the parameters passed when the parent process calls popen. The definitions of popen and pclose are given below:
03 |
Function: popen () calls fork () to generate a sub-process, and then calls/bin/sh-C from the sub-process to execute the command of the parameter command. |
04 |
You can use "R" to indicate reading, and "W" to indicate writing. |
05 |
According to this type value, popen () establishes a pipeline to connect to the standard output device or standard input device of the child process, and then returns a file pointer. |
06 |
Then the process can use this file pointer to read the output device of the sub-process or write it to the standard input device of the sub-process. |
07 |
Returned value: if the operation succeeds, the file pointer is returned. Otherwise, null is returned. The error cause is stored in errno. |
09 |
FILE * popen( const char * command,const char * type); |
12 |
Function: pclose () is used to close the pipeline and file pointer created by popen. The parameter stream is the object pointer returned by the previous popen (). |
13 |
Return Value: If the return result is successful, the return result is-1, and the cause is stored in errno. |
15 |
int pclose(FILE * stream); |
The following example shows how to use popen:
If we want to obtain the number of files in the current directory, we can use:
We can write in the program as follows:
01 |
/* Obtain the number of files in the current directory */ |
11 |
char result_buf[MAXLINE], command[MAXLINE]; |
12 |
int rc = 0; // Receives the return value of a command. |
15 |
/* Write the command to be executed to Buf */ |
16 |
snprintf(command, sizeof(command), "ls ./ | wc -l"); |
18 |
/* Execute the preset command and read the standard output of the command */ |
19 |
fp = popen(command, "r"); |
22 |
perror("Popen execution failed! "); |
25 |
while(fgets(result_buf, sizeof(result_buf), fp) != NULL) |
27 |
/* Remove the line break returned by the command for better output below */ |
28 |
if(‘\n‘ == result_buf[strlen(result_buf)-1]) |
30 |
result_buf[strlen(result_buf)-1] = ‘\0‘; |
32 |
printf("Command [% s] Output [% s] \ r \ n", command, result_buf); |
35 |
/* Wait for the command to be executed and close the pipeline and file pointer */ |
39 |
perror("Failed to close file Pointer"); |
44 |
printf("Command [% s] subprocess end status [% d] command return value [% d] \ r \ n", command, rc, WEXITSTATUS(rc)); |
Compile and execute:
$ GCC popen. c
$./A. Out
Command [ls./| WC-L] to output [2]
Command [ls./| WC-L] sub-process end status [0] command return value [0]
The above popen only captures the standard output of the command. If the command fails to be executed, the sub-process prints the error information to the standard output, and the parent process cannot obtain the error information. For example, if the command is "ls nofile.txt", then the shell will output "ls: nofile.txt: no such file or directory ". This output is on the standard error output. It cannot be obtained through the above program.
Note: If you set the command in the above program to "ls nofile.txt", compile and execute the program and you will see the following results:
$ GCC popen. c
$./A. Out
Ls: nofile.txt: no such file or directory
Command [ls nofile.txt] subprocess end status [256] command return value [1]
Note that the first line of output is not the output of the parent process, but the standard error output of the child process.
Sometimes the error information of a child process is very useful. How can a parent process obtain the error information of a child process?
Here we can redirect the error output of the child process to the standard output (2> & 1) so that the parent process can capture the error information of the child process. For example, if the command is "ls nofile.txt 2> & 1", the output is as follows:
Command [ls nofile.txt 2> & 1] to output [ls: nofile.txt: no such file or directory]
Command [ls nofile.txt 2> & 1] sub-process end status [256] command return value [1]
Appendix: Macro involved in determining the termination status of a sub-process. Set the Process Termination status to status.
Wifexited (Status) is not 0 if the sub-process ends normally.
Wexitstatus (Status) gets the end code returned by the sub-process exit (). Generally, wifexited is used to determine whether the macro can be used until it ends normally.
Wifsignaled (Status) If the sub-process ends because of a signal, the macro value is true.
Wtermsig (Status) gets the signal code of the sub-process terminated due to the signal. Generally, this macro is used only after wifsignaled is used for determination.
Wifstopped (Status) If the sub-process is paused, the macro value is true. This is generally the case only when wuntraced is used.
Wstopsig (Status) gets the signal code that causes the sub-process to pause. This macro is generally used only after wifstopped is used for determination.