Linux c program to obtain the shell script output method

  • 2020-04-02 01:27:13
  • OfStack

1. Introduction
There is a famous saying in Unix: "one line of shell script is better than ten thousand lines of C program", although this sentence is a bit exaggerated, but there is no denying that with the script can greatly simplify some programming work. For example, implementing a ping program to test network connectivity requires 200 to 300 lines of code to implement the ping function. Why not call the ping command of the system directly? Shell commands are usually called in a program through the system function. However, the system function only returns whether the command executed successfully, and we might need to get the result of the shell command output on the console. For example, after the execution of the external command ping, if the execution fails, we want to get the information back from the ping.

2. Use temporary files
The first method that comes to mind is to redirect the command output to a temporary file, read the temporary file in our application, and get the execution result of the external command, as shown below:


#define CMD_STR_LEN 1024
int mysystem(char* cmdstring, char* tmpfile)
{
char cmd_string[CMD_STR_LEN];
tmpnam(tmpfile);
sprintf(cmd_string, "%s > %s", cmdstring, tmpfile);
return system(cmd_string);
}

This kind of use USES the temporary file as the bridge between the application and the external command, in the application needs to read the file, and then delete the temporary file, more cumbersome, the advantage is simple, easy to understand. Is there a way to do this without resorting to temporary files?

3. Use anonymous pipes
in < < Advanced programming for UNIX environments > > The book gives an example of an anonymous pipeline to output program results to a paging program, so it occurred to us that we could also pipe the results of external commands to the application. The method is to fork a child process, and create an anonymous pipeline, in the child process to execute the shell command, and its standard output dup to the input of the anonymous pipeline, the parent process read from the pipeline, can get the output of the shell command, the code is as follows:



int mysystem(char* cmdstring, 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)     
{
close(fd[1]);     
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    
{
close(fd[0]);     
if (fd[1] != STDOUT_FILENO)
{
if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO)
{
return -1;
}
close(fd[1]);
}
if (execl("/bin/sh", "sh", "-c", cmdstring, (char*)0) == -1)
return -1;
}
return 0;
}

4. Use popen
In the process of learning Unix programming, I found that the system also provided a popen function, which can be very simple to handle the call shell, its function prototype is as follows:
FILE *popen(const char *command, const char *type);
This function creates a pipe, forks a process, and then executes the shell, whose output can be obtained by reading a file. This method, which avoids creating temporary files and is not limited by the number of output characters, is recommended.
Popen USES a FIFO pipe to execute external programs.

#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);

Popen determines the command's input/output direction by whether the type is r or w, with r and w relative to the command's pipes. R means that command reads in from the pipe, w means that command outputs through the pipe to its stdout, and popen returns a pointer to the file stream for the FIFO pipe. Pclose is used to close the pointer after use.
Here's an example:

#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) );//Initializes the buf so that it doesn't end up in a file
stream = popen( "ls -l", "r" ); //Read the output of the "ls-l" command through the pipe (the "r" parameter) to the FILE* stream
wstream = fopen( "test_popen.txt", "w+"); //Create a new writable file
fread( buf, sizeof(char), sizeof(buf), stream); //Read the data stream from the FILE* stream into buf
fwrite( buf, 1, sizeof(buf), wstream );//Write the data from buf to FILE  & have spent & have spent *wstream corresponding to the stream, is also written to the file
pclose( stream );
fclose( wstream );
return 0;
}
[root@localhost src]# gcc popen.c
[root@localhost src]# ./a.out
[root@localhost src]# cat test_popen.txt
 A total of  128
-rwxr-xr-x 1 root root 5558 09-30 11:51 a.out
-rwxr-xr-x 1 root root 542 09-30 00:00 child_fork.c
-rwxr-xr-x 1 root root 480 09-30 00:13 execve.c
-rwxr-xr-x 1 root root 1811 09-29 21:33 fork.c
-rwxr-xr-x 1 root root 162 09-29 18:54 getpid.c
-rwxr-xr-x 1 root root 1105 09-30 11:49 popen.c
-rwxr-xr-x 1 root root 443 09-30 00:55 system.c
-rwxr-xr-x 1 root root    0 09-30 11:51 test_popen.txt
-rwxr-xr-x 1 root root 4094 09-30 11:39 test.txt

5. Summary
Statistics show that the rate of code defects is constant, regardless of the language used. Linux provides a number of utilities and scripts that can be invoked in a program, which undoubtedly simplifies the program and reduces the number of bugs in the code. Linux shell scripting is also a powerful tool that lets you write scripts as needed and then invoke custom scripts in your programs.


Related articles: