Let's take a look at the figure below:
When I/O redirection is performed, only the FD of different input tables points to the same file table structure.
The following important functions are used for I/O redirection:
int dup( int oldfd );int dup2( int oldfd, int targetfd )
Using the DUP function, we can copy a descriptor. If a descriptor is passed to the function, it returns a new descriptor, which is a copy of the descriptor sent to it, that is, they will share the same file table.
In dup2, the structure of the file table pointed to by oldfd is copied to the file table structure pointed to by targetfd, so that targetfd is redirected to oldfd and directed to the file table structure referred to by oldfd.
The following program uses pipelines and redirection to communicate between two processes.
Two child processes A and B are created in the parent process, and the pipeline a_to_ B [2] is created in the parent process.
Our task is to use the output of process A as the input of process B.
To this end, first redirect the standard output of sub-process a to the write end of the pipeline a_to_ B [1], then, in sub-process B, redirect the read end a_to_ B [0] of the pipeline to the standard input of B.
The following code is used:
Int a_to_ B [2]; // Save the pipeline Descriptor
If (pipe (a_to_ B) <0) // create a pipeline
{
Printf ("An error occurred while creating the MPs queue! ");
Exit (0 );
}
If (Fork () = 0) {// This is sub-process 1
Close (a_to_ B [0]); // close the read end
If (dup2 (a_to_ B [1], stdout_fileno )! = Stdout_fileno) {// the output of sub-process 1 is redirected to the input of the Pipeline
Printf ("redirection failed! ");
Exit (0 );
}
Close (a_to_ B [1]);
Execvp (export _a-> exe_path, export _a-> argv );
}
If (Fork () = 0) {// This is sub-process 2
Close (a_to_ B [1]); // closes the write end for process 2.
Dup2 (a_to_ B [0], stdin_fileno); // the output of the MPs queue is redirected to the input of sub-process 2.
Close (a_to_ B [0]);
Execvp (export _ B-> exe_path, export _ B-> argv );
}
Else {// parent process
Wait (null );
}
Obtain shell script output in Linux C program (for example, obtain system command output)
1. Preface
There is a famous saying in UNIX: "A shell script is better than a million lines of C Programs, script can greatly simplify some programming work. For example, to implement a Ping program to test network connectivity, write 200 ~ to implement the Ping function ~ Why can't I directly call the ping command of the System for the first line of code? GenerallySystemFunction to call shell commands. However,SystemThe function only returns whether the command is successfully executed, and we may need to obtain the shell command on the console.Output. For example,
If the external command Ping fails, we want to get the ping response.
2. Use temporary files
The first thought of method isOutputRedirect to a temporary file, read the temporary file in our application, and obtain the external command execution result. The Code is as follows:
# Define pai_str_len 1024
Int mysystem (char * struct string, char * tmpfile)
{
Char character _string [character _str_len];
Tmpnam (tmpfile );
Sprintf (optional _string, "% S> % s", optional string, tmpfile );
ReturnSystem(Pai_string );
}
The temporary file is used as a bridge between the application and external commands, and the file needs to be read and deleted in the application, which is cumbersome and easy to implement, easy to understand. Is there any way to avoid using temporary files?
3. Use an anonymous Pipeline
In the <advanced programming in UNIX environment> book, a program result is presented using an anonymous pipeline.OutputThe example of the paging program, so we can also connect the results of external commands with the application through pipelines. The method is to fork a sub-process, create an anonymous pipeline, execute shell commands in the sub-process, and set its standardOutputFrom DUP to the input end of the anonymous pipeline, the parent process reads data from the pipeline to obtain the shell commandOutputThe Code is as follows:
/**
* EnhancedSystemFunction that can returnSystemCalledOutput
*
* @ Param [in] using string refers to the command string for calling an external program or script
* @ Param [out] Buf returns the buffer of the external command result
* @ Param [in] Len buffer Buf Length
*
* @ Return 0: Successful;-1: Failed
*/
Int mysystem (char * character string, char * Buf, int Len)
{
Int FD [2];
Pid_t PID;
Int N, count;
Memset (BUF, 0, Len );
If (pipe (FD) <0)
Return-1;
If (pid = fork () <0)
Return-1;
Else if (pid> 0)/* parent process */
{
Close (FD [1]);/* close write end */
Count = 0;
While (n = read (FD [0], BUF + count, Len)> 0 & COUNT> Len)
Count + = N;
Close (FD [0]);
If (waitpid (PID, null, 0)> 0)
Return-1;
}
Else/* child process */
{
Close (FD [0]);/* close read end */
If (FD [1]! = Stdout_fileno)
{
If (dup2 (FD [1], stdout_fileno )! = Stdout_fileno)
{
Return-1;
}
Close (FD [1]);
}
If (execl ("/bin/sh", "sh", "-c", character string, (char *) 0) =-1)
Return-1;
}
Return 0;
} 4. Use popen
In the process of learning Unix programming, it is found that the system also provides a popen function, which can easily process shell calls. Its function prototype is as follows:
File * popen (const char * command, const char * type );
This function is used to create a pipeline, fork a process, and then execute shell, while ShellOutputIt can be obtained by reading files. This method avoids creating temporary filesOutputIt is recommended to use the limit on the number of characters.
Popen uses a FIFO pipeline to execute external programs.
# Include <stdio. h>
File * popen (const char * command, const char * type );
Int pclose (File * stream );
Popen determines the command input through whether the type is R or W/OutputDirection. R and W are relative to the command pipeline. R indicates that the command is read from the pipeline, W indicates that the command is passed through the pipelineOutputTo its stdout, popen returns the file stream pointer of the FIFO pipeline. Pclose is used to close the pointer after use.
The following is an example:
/*************************************** **************************************** ************
** Name: popen. c
** This program is used to show the usage of popen ().
**************************************** **************************************** ***********/
# Include <sys/types. h>
# Include <unistd. h>
# Include <stdlib. h>
# Include <stdio. h>
# Include <string. h>
Int main (void)
{
File * stream;
File * wstream;
Char Buf [1024];
Memset (BUF, '\ 0', sizeof (BUF); // initialize the Buf to avoid gibberish in the file.
Stream = popen ("ls-L", "R"); // setOutputRead ("R" parameter) to file * stream through pipelines
Wstream = fopen ("test_popen.txt", "W +"); // create a writable file
Fread (BUF, sizeof (char), sizeof (BUF), stream); // read the data stream of file * stream to Buf.
Fwrite (BUF, 1, sizeof (BUF), wstream); // write the data in the Buf to the stream corresponding to file * wstream, which is also written to the file
Pclose (Stream );
Fclose (wstream );
Return 0;
}
5. Summary
Statistics show that the defect rate of the Code is certain and has nothing to do with the language used. Linux provides many utility tools and scripts. Calling tools and scripts in a program can undoubtedly simplify the program and reduce the number of defects in the code. Linux Shell script is also a powerful tool. We can compile scripts as needed and then call custom scripts in the program.
Let's take a look at the figure below:
When I/O redirection is performed, only the FD of different input tables points to the same file table structure.
The following important functions are used for I/O redirection:
int dup( int oldfd );int dup2( int oldfd, int targetfd )
Using the DUP function, we can copy a descriptor. If a descriptor is passed to the function, it returns a new descriptor, which is a copy of the descriptor sent to it, that is, they will share the same file table.
In dup2, the structure of the file table pointed to by oldfd is copied to the file table structure pointed to by targetfd, so that targetfd is redirected to oldfd and directed to the file table structure referred to by oldfd.
The following program uses pipelines and redirection to communicate between two processes.
Two child processes A and B are created in the parent process, and the pipeline a_to_ B [2] is created in the parent process.
Our task is to use the output of process A as the input of process B.
To this end, first redirect the standard output of sub-process a to the write end of the pipeline a_to_ B [1], then, in sub-process B, redirect the read end a_to_ B [0] of the pipeline to the standard input of B.
The following code is used:
Int a_to_ B [2]; // Save the pipeline Descriptor
If (pipe (a_to_ B) <0) // create a pipeline
{
Printf ("An error occurred while creating the MPs queue! ");
Exit (0 );
}
If (Fork () = 0) {// This is sub-process 1
Close (a_to_ B [0]); // close the read end
If (dup2 (a_to_ B [1], stdout_fileno )! = Stdout_fileno) {// the output of sub-process 1 is redirected to the input of the Pipeline
Printf ("redirection failed! ");
Exit (0 );
}
Close (a_to_ B [1]);
Execvp (export _a-> exe_path, export _a-> argv );
}
If (Fork () = 0) {// This is sub-process 2
Close (a_to_ B [1]); // closes the write end for process 2.
Dup2 (a_to_ B [0], stdin_fileno); // the output of the MPs queue is redirected to the input of sub-process 2.
Close (a_to_ B [0]);
Execvp (export _ B-> exe_path, export _ B-> argv );
}
Else {// parent process
Wait (null );
}