It is said that statistical data indicate that the defect rate of code is certain, regardless of the language used. Linux provides a lot of utilities and scripts to invoke tools and scripts in a program that can simplify programs and reduce the number of code flaws. Linux shell script is also a powerful tool, we can script as needed, and then call custom script in the program.
One sentence in Unix programming art is that a row of Shell scripts is better than Wan C. So in Linux programming, how does the C program call the shell command and how does it get the return result of the command? Let's take a look at it together. 1. Call Shell command
In general, there are three common ways to invoke shell commands in a Linux system using the C Program: System (), Popen (), EXEC series functions. Using System () does not require a user to create a process because it is already encapsulated, directly to the shell command, and Popen () to execute the shell command with less overhead than system (); Exec requires a user fork/vfork process, and then exec The required shell command. 1.1 system () function Prototypes
int system (const char *command);
function Description
System () invokes the fork () to produce the child process, which invokes the/BIN/SH-C string to execute the command represented by the parameter string string, which then returns the process of the original call. The SIGCHLD signal is temporarily shelved during the call to System () and the SIGINT and sigquit signals are ignored. return value
If system () fails while calling/bin/sh, 127 is returned, and the other failure reason returns-1. If the argument string is a null pointer (null), a value other than 0 is returned. If the system () call succeeds, the return value after executing the shell command is finally returned, but this return value is also likely to return 127 for system () call/bin/sh failure, so it is best to check errno again to confirm execution success. Additional Instructions
Do not use System () when writing programs with Suid/sgid permissions, because system () inherits environment variables, which can cause problems with systems security through environment variables. Sample
#include <stdlib.h>
int main (int argc, char *argv[])
{
system ("Ls-al/etc/passwd/etc/shadow");
return 0;
}
1.2 popen ()
function Prototypes
FILE *popen (const char *command, const char *type);
int Pclose (FILE *stream);
function Description
Popen () invokes fork () to produce the child process, and then calls/bin/sh-c from the child process to execute the command of the parameter command. The parameter type can be read by using "R", and "w" for writing. According to this type value, Popen () establishes a standard output device or standard input device that is attached to a subprocess, and then returns a file pointer. The process can then use this file pointer to read the output device of a child process or to a standard input device that is written to a child process. In addition, all other functions that use the file pointer (files *) operation are available except for the fclose (). return value
If successful, return the file pointer, otherwise NULL is returned, and the reason for the error is stored in the errno. Attention Matters
Try to avoid using popen () when writing programs with Suid/sgid permissions, because Popen () inherits environment variables, which can cause system security problems through environment variables. Sample
#include <stdio.h>
int main (int argc, char *argv[])
{
FILE *fp;
Char buffer[80];
Fp=popen ("cat/etc/passwd", "R");
Fgets (buffer,sizeof (buffer), FP);
printf ("%s", buffer);
return 0;
}
1.3 exec function cluster
function Prototypes
int execl (const char *path, const char *arg, ...);
int EXECLP (const char *file, const char *arg, ...);
int execle (const char *path, const char *arg, ..., Char *const envp[]);
int execv (const char *path, char *const argv[]);
int EXECVP (const char *file, char *const argv[]);
int Execve (const char *path, char *const argv[], char *const envp[];
Sample
Creates a new subprocess using Vfork (), and then calls the EXEC function family.
#include <unistd.h>
#include <stdio.h>
int main (int argc, char *argv[])
{
char *args[] = { "LS", "-al", "/etc/passwd"};
if (vfork () = = 0)
{
execv ("/bin/ls", args);
}
else
{
printf ("This is the parent process\n");
}
return 0;
}
2. Get return result
We've shown several ways to invoke the shell command in C programs, where we find a problem--although we can tell if the shell command was executed, but sometimes we can't get the information it returns. Well, then you can consider the following methods. 2.1 Using temporary files
The easiest way to think first is to redirect the shell command output to a temporary file, read the temporary file in our application, and get the results of the external command execution.
The code looks like this:
#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 use of temporary files as a bridge between application and external commands, the need to read files in the application, and then delete the temporary file, more cumbersome, the advantage is simple, easy to understand. 2.2 using anonymous pipes
In the UNIX Environment Advanced Programming (APUE) book gives an example of an anonymous pipeline that outputs program results to a paging program, and it is thought that we can also use pipelines to connect the results of external commands to the application. The method is to fork a subprocess, create an anonymous pipe, execute the shell command in the subprocess, and DUP its standard output to the input of the anonymous pipe, and the parent process reads from the pipe to get the output of the shell command.
The code looks like this:
/** * Enhanced system function that returns the output of the system call * @param [in] cmdstring a command string that invokes an external program or script @param [out] buf a buffer * that returns the result of an external command @para M[in] Len Buffer buf length * * @return 0: successful;
-1: Failed/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)/* 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_fi LENO) {return-1;
Close (fd[1]);
} if (Execl ("/bin/sh", "sh", "C", Cmdstring, (char*) 0) = = 1) {return-1;
} return 0; }
2.3 using Popen ()
In the example of executing the shell command, we used the Popen () function, which you may have discovered, using Popen () to get the return result of the command.
The function is to create a pipe, fork a process, and then execute the shell, and the shell's output can be obtained by reading the file. This method avoids the creation of temporary files and is not limited by the number of output characters, and is recommended for use.
Popen () uses FIFO pipes to execute external programs. It determines the command's input/output direction by Type R or W, and R and W are relative to the command's pipe. R indicates that the command is read from the pipe, and W represents the file stream pointer that the command outputs to its stdout,popen () from the pipe to the FIFO pipe. Pclose () is used to close this pointer when the end is used.
The sample code looks like this:
#include <stdio.h> #include <string.h> int main (int argc,char*argv[]) {
FILE *fstream = NULL;
Char buff[1024];
memset (buff, 0, sizeof (buff)); if (NULL = = FStream = Popen ("Ifconfig", "R"))) {fprintf (stderr, "Execute command failed:%s", Strerro
R (errno));
return-1;
while (NULL!= fgets (buff, sizeof (buff), fstream)) {printf ("%s", buff);
} pclose (FStream);
return 0; }