El lenguaje C ejecuta comandos de shell (sistema operativo popen pipe)

A veces necesitamos ejecutar algunos comandos de shell en lenguaje C u obtener algunos datos devueltos a través de comandos de shell.

No es necesario devolver el sistema / exec de resultados

Si no regresa después de ejecutar el comando, entonces el más utilizado es utilizar directamente el sistema
, como

sysytem("reboot")

Puede usar las funciones de la familia ejecutiva y devolver -1 en caso de falla

#include <unistd.h>

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[]);

De hecho, la implementación del sistema se llama función execl

int system(const char *cmdstring)
{
	pid_t pid;
	int status;
	if (cmdstring == NULL)
	{
		return (1);
	}
	if ((pid = fork()) < 0)
	{
		status = -1;
	}
	else if (pid == 0)
	{
		execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
		_exit(127);
	}
	else
	{
		while (waitpid(pid, &status, 0) < 0)
		{
			if (errno != EINTR)
			{
				status = -1;
				break;
			}
		}
	}
	return(status);
 } 

Necesidad de devolver la ejecución resultado-popen

A veces necesitamos devolver información de datos, como la ejecución ls -l, entonces no podemos usar el sistema

Es necesario usar popen para lograrlo, popen siempre se usa junto con pclose.

popen () crea una tubería, bifurca o invoca un proceso secundario y luego ejecuta el comando.

El valor de retorno está en la secuencia de E / S estándar. Debido a que está en la tubería, la secuencia de datos es unidireccional. El comando solo puede generar stdout o leer stdin, por lo que el tipo tiene solo dos valores: 'w' o 'r'.

r significa que el comando lee el flujo de datos de la tubería, y w significa que la salida estándar del comando se envía a la tubería. El comando no puede leerse y enviarse al mismo tiempo. popen devuelve el puntero del flujo de datos FIFO.

Como sigue:

En general, el ampersand debe ser filtrado

#define CMD_LEN         128
#define BUF_LEN         1400

void execute_cmd(const char* cmd, char* buf, int buf_len)
{
    int     status = -1;
    FILE*   fp;
    char*   p;
    char    pwd[CMD_LEN] = "";
    char unpadding[CMD_LEN];
    char fgets_buf[512];
    int len;
    int end;

    if (buf == NULL || buf_len <= 0)
    {
        return;
    }
    
    len = strlen(cmd);
    end = (int)cmd[len - 1]; 

    /* unpadding */
    memset(unpadding, 0, sizeof(unpadding));
    if (end < len) {
        memcpy(unpadding, cmd, len - end);
    } else {
        memcpy(unpadding, cmd, len);
    }   

    if ((p = strchr(unpadding, '\n')) != NULL) {
        strncpy(pwd, unpadding, p - unpadding);
        ++p;
    }   
    else
        exit(0);

    printf("execute cmd = %s\n", p);

    if ('&' == p[strlen(p) - 1]) {
        status = system(p);
        sprintf(buf, "%d", WEXITSTATUS(status));
    } else {
        fp = popen(p, "r");

        if (fp != NULL)
        {
            while (fgets(fgets_buf, sizeof(fgets_buf), fstream))
            {
                if (len < sizeof(buf))
                {
                    len += snprintf(buf+len, sizeof(buf)-len, "%s", buff);
                }
            }
            pclose(fp);
        }
    }
}

Necesita devolver la canalización de resultados anónimos de ejecución

Utilice la canalización para obtener la información devuelta al ejecutar el comando de shell. El proceso general es el siguiente

  • 1. Crear proceso, crear canalización anónima
  • 2. El proceso secundario utiliza el descriptor de copia de la función dup para vincular la salida estándar de la línea de comandos del shell al final de escritura de la canalización
  • 3. El proceso padre lee datos del final de lectura de la canalización

función de tubería

  • Archivo de encabezado requerido: #include <unistd.h>
  • Prototipo de la función: int pipe (int fd [2]);
  • Valor de retorno: retorno exitoso 0, retorno de error -1

función dup

  • Redireccionar https://blog.csdn.net/tiandc/article/details/81489447
#include<stdio.h> 
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
int main()
{
	int fpipe[2] = {0};
	pid_t fpid;
	char massage[1000] = {0};
	memset(massage, 0, 20);
	if (pipe(fpipe) < 0)
	{
		printf("Create pipe error!\n");
	}
	fpid = fork();
	if (fpid == 0)
	{
		close(fpipe[0]);
		dup2(fpipe[1],STDOUT_FILENO);
		system("ls");
	}
	else if (fpid > 0)
	{
		wait(NULL);
		printf("this is father,recieve:");
		fflush(stdout);
		close(fpipe[1]);
		read(fpipe[0], massage, 1000);
		printf("%s\n",massage);
	}
	else
	{
		printf("create fork error!\n");
	}
	return 0;
}

Otra forma de pensar: la famosa tubería quince

Independientemente de si es sysytem o popen, realmente bifurcará un proceso internamente, lo que en realidad consume mucho sistema. Ahora la compañía ha implementado un método, pero nunca he entendido por qué no puede consumir recursos.

La forma de implementación es así

一个单独的vshd.sh脚本,一开机就后台运行,然后创建fifo,一直在等待接收数据。

C语言里面每次要执行命令时,就把命令发给vshd.sh监听的管道,再创建一个新的管道用来等待接收vshd.sh将执行完的命令返回给C语言。

这样每次要执行命令时都不调用system/popen,而是通过管道发送给vshd.sh后台脚本来执行。

Referencias
https://blog.csdn.net/qq_27664167/article/details/82194391

106 artículos originales publicados · 76 elogiados · 130,000 visitas +

Supongo que te gusta

Origin blog.csdn.net/Creator_Ly/article/details/104145680
Recomendado
Clasificación