Linux中的shell命令执行

目录

1. popen 和 pclose系列

1.1 popen

1.2 pclose

1.3 fgets和fputs

1.4 fread和fwrite

1.5 strerror

1.6 完整使用实例

2. system系列

2.1 system函数

2.2 使用实例


1. popen 和 pclose系列

popen 和 pclose 是 C 语言标准库中的函数,它们允许程序员在 C 程序中执行 shell 命令,并能够读取命令的输出或向命令发送输入,通常结合fgets。

1.1 popen

popen 函数是 C 语言标准库中的一个函数,用于在程序中执行 shell 命令,并允许程序读取命令的输出或向命令发送输入。这个函数在头文件 <stdio.h> 中定义。popen 函数的原型如下:

FILE *popen(const char *command, const char *type);
  • command一个字符串,表示要执行的 shell 命令,例如“ls -l”。
  • type一个字符串,表示管道的类型,它可以是 "r" 或 "w"。

popen 通过 type 参数的值来决定如何处理命令的输入和输出:

  • 如果 type 是 "r",popen 会创建一个管道,并将文件指针连接到命令的标准输出。这意味着你可以通过返回的文件指针读取命令的输出。
  • 如果 type 是 "w",popen 会创建一个管道,并将文件指针连接到命令的标准输入。这意味着你可以通过返回的文件指针向命令写入数据。

返回值:

  • 如果 popen 调用成功,它返回一个 FILE 指针,该指针可以用于读取或写入命令的输出或输入。
  • 如果 popen 调用失败,它返回 NULL,并且 errno 会被设置为指示错误的值。
  • 通过 popen 返回的 FILE 指针,可以使用标准的 I/O 函数(如 fread、fwrite、fgets、fputs 等)来读取或写入命令的输出或输入。

注意事项:

  1. 使用 popen 时,需要注意命令执行的权限问题,确保程序有足够的权限执行命令。
  2. 如果 popen 调用失败,它将返回 NULL。在尝试读取或写入管道之前,应检查返回值。
  3. popen 返回的 FILE 指针是临时的,当 pclose 被调用时,它会自动关闭。
  4. 如果 pclose 调用失败,它会返回 -1,并设置 errno。

1.2 pclose

pclose 函数是 C 语言标准库中的一个函数,用于关闭之前通过 popen 函数打开的管道,并等待管道中的子进程完成执行。这个函数在头文件 <stdio.h> 中定义。pclose 函数的原型如下:

int pclose(FILE *stream);

  • stream:由 popen 返回的文件指针。

返回值:

  • 如果 pclose 调用成功,它返回子进程的退出状态码,这是一个整数值。
  • 如果 pclose 调用失败,它返回 -1,并设置 errno。

子进程的退出状态码是一个整数值,通常在 0 到 255 之间。不同的值表示不同的情况:

  • 0:子进程正常退出。
  • 非零值:子进程异常退出,通常表示错误或异常情况。

注意事项:

  1. 在调用 pclose 之前,子进程必须已经完成执行。如果子进程还在运行,pclose 将等待子进程完成。
  2. pclose 调用会关闭由 popen 打开的管道,因此你不能在调用 pclose 之后继续通过该管道读取或写入数据。
  3. 如果 popen 调用失败,或者 popen 返回的 FILE 指针为 NULL,尝试调用 pclose 会导致未定义行为。
  4. 如果 pclose 返回 -1,你需要检查 errno 来确定是否发生了错误。

它返回命令的退出状态码,这与在 shell 中执行命令后使用 echo $? 查看的退出状态码相同。

1.3 fgets和fputs

fgets 函数是 C 语言标准库中的一个函数,用于从文件指针指向的文件中读取一行文本。这个函数在头文件 <stdio.h> 中定义。
fgets函数原型如下:

char *fgets(char *str, int n, FILE *stream);
  • str:一个指向字符数组的指针,用于存储读取的数据。
  • n:一个整数,表示最多读取的字符数(包括字符串结束符 \0)。
  • stream:一个指向 FILE 对象的指针,指向要读取数据的文件。

返回值:

  • 如果成功读取了 n-1 个字符,fgets 返回 str 指针。
  • 如果到达文件末尾,fgets 返回 str 指针,且不会在 str 末尾添加字符串结束符 \0。
  • 如果读取过程中发生错误,fgets 返回 NULL,并且 errno 会被设置为指示错误的值。

特点:

  1. fgets 不会检查文件是否已成功打开。如果 stream 指向的文件未成功打开,调用 fgets 可能会导致未定义行为。
  2. fgets 不会读取超过 n-1 个字符,即使遇到换行符或文件末尾。
  3. 如果 fgets 返回 NULL,你需要检查 errno 来确定是否发生了错误。

fputs函数原型如下:

int fputs(const char *str, FILE *stream);
  • str:一个指向字符串的指针。
  • stream:指向 FILE 对象的指针,表示要写入数据的文件。

返回值:

  • 如果成功写入所有字符,fputs 返回 0。
  • 如果写入过程中发生错误,fputs 返回 EOF,并且 errno 会被设置为指示错误的值。

特点:

  1. fputs 不会在字符串末尾添加字符串结束符 \0。
  2. fputs 不会检查文件是否已成功打开。如果 stream 指向的文件未成功打开,调用 fputs 可能会导致未定义行为。
  3. 如果 fputs 返回 EOF,你需要检查 errno 来确定是否发生了错误。

注意事项:

  • 数据类型:fgets 和 fputs 处理的是文本数据,它们会处理换行符和其他字符编码。
  • 错误处理:fgets 返回读取的行,如果到达文件末尾或发生错误,返回 NULL。fputs 返回 0 表示写入失败,通常在写入字符串后立即返回。
  • 缓冲区:fgets 和 fputs 函数考虑了缓冲区,如果流是缓冲的,它们可能会在写入磁盘之前在缓冲区中积累数据。

1.4 fread和fwrite

fread 和 fwrite 函数用于读取和写入二进制数据,而 fgets 和 fputs 函数用于读取和写入文本数据。这些函数的主要区别在于它们处理数据的方式和它们对数据格式的期望。

fread函数原型如下:

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

  • ptr:一个指向要读取数据的内存地址的指针。
  • size:每个元素的大小(以字节为单位)。
  • nmemb:要读取的元素数量。
  • stream:指向 FILE 对象的指针,表示要读取数据的文件。

fread函数原型如下:

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

  • ptr:一个指向要写入数据的内存地址的指针。
  • size:每个元素的大小(以字节为单位)。
  • nmemb:要写入的元素数量。
  • stream:指向 FILE 对象的指针,表示要写入数据的文件。

注意事项:

  1. 数据类型:fread 和 fwrite 不关心数据的类型,它们会将数据作为二进制字节序列读取和写入。
  2. 错误处理:这两个函数返回实际读取或写入的元素数量。如果读取或写入过程中发生错误,返回值可能小于请求的数量,并且 errno 会被设置。
  3. 缓冲区:这两个函数不会处理换行符或字符编码,它们直接读取和写入字节。

1.5 strerror

使用 popen 和 pclose 时,需要注意命令执行的权限问题,确保程序有足够的权限执行命令。

  • 如果 popen 调用失败,它将返回 NULL。在尝试读取或写入管道之前,应检查返回值。pclose 返回命令的退出状态码。
  • 如果 pclose 调用失败,它将返回 -1,并设置 errno。

而strerror 函数是 C 语言标准库中的一个函数,它用于将错误号(errno 变量)转换为对应的字符串表示形式。这个函数在头文件 <string.h> 中定义。
strerror 函数的原型如下:

char *strerror(int errnum);

  • errnum:一个整数,表示要转换的错误号。通常这个值是在系统调用或函数失败时设置的 errno 变量的值。

strerror返回一个指向静态字符串的指针,该字符串描述了 errnum 参数所表示的错误。这个字符串包含了错误消息,通常包括错误号和错误描述。需要注意,strerror 函数返回的字符串是静态的,每次调用都会覆盖之前的调用结果。因此,如果需要在多次调用之间保持错误消息,应该将返回的字符串复制到自己的缓冲区中。

1.6 完整使用实例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main() {
    FILE *fp;
    char command[256];
    char buffer[256];
    char input[] = "Hello, world!\n";
    int status;

    // 定义要执行的 shell 命令
    strcpy(command, "./your_command");

    // 使用 popen 执行命令并获取其输出
    fp = popen(command, "w");
    if (fp == NULL) {
        perror("popen failed");
        exit(EXIT_FAILURE);
    }

    // 使用 fputs 向命令发送输入数据
    if (fputs(input, fp) == EOF) {
        perror("fputs failed");
        pclose(fp);
        exit(EXIT_FAILURE);
    }

    // 关闭管道
    pclose(fp);

    // 使用 popen 重新打开命令以读取输出
    fp = popen(command, "r");
    if (fp == NULL) {
        perror("popen failed");
        exit(EXIT_FAILURE);
    }

    // 使用 fgets 读取命令的输出
    if (fgets(buffer, sizeof(buffer), fp) == NULL) {
        perror("fgets failed");
        pclose(fp);
        exit(EXIT_FAILURE);
    }

    // 打印读取的输出
    printf("Output: %s", buffer);

    // 获取子进程的退出状态码
    status = pclose(fp);
    if (status == -1) {
        perror("pclose failed");
        exit(EXIT_FAILURE);
    }

    // 打印子进程的退出状态码
    if (WIFEXITED(status)) {
        printf("Child process exited with status %d\n", WEXITSTATUS(status));
    } else {
        printf("Child process did not exit normally\n");
    }

    exit(EXIT_SUCCESS);
}

上例中首先定义了一个 shell 命令 your_command,它应该是一个可执行文件,可以向其发送输入并读取输出。

  1. 使用 popen 首先以写入模式打开管道,向其中发送一个字符串 input。
  2. 关闭管道并再次以读取模式打开管道。
  3. 使用 fgets 读取命令的输出,并使用 printf 打印出来。
  4. 使用 pclose 关闭管道,并检查子进程的退出状态码。

2. system系列

2.1 system函数

system 函数是 C 语言标准库中的一个函数,用于执行一个 shell 命令,并等待命令完成执行。这个函数在头文件 <stdlib.h> 中定义。system函数原型如下:

int system(const char *command);

参数:

  • command:一个指向 const char 的指针,它包含了要执行的 shell 命令。

返回值:

  • 如果 system 调用成功,它返回最后一个执行的命令的退出状态码,这是一个整数值。
  • 如果 system 调用失败,它返回 -1,并设置 errno。

返回值的意义

  • 子进程的退出状态码通常在 0 到 255 之间。不同的值表示不同的情况:
  • 0:子进程正常退出。
  • 非零值:子进程异常退出,通常表示错误或异常情况。

注意事项:

  1. 使用 system 时,需要注意的是,它会启动一个新进程来执行命令,这可能会增加程序的运行时间和资源消耗。
  2. system 函数返回最后一个命令的退出状态码。如果命令执行失败,它将返回一个非零值。
  3. 在某些环境中,system 函数可能不会正确处理错误,因此,对于错误处理,可能需要额外的检查。

2.2 使用实例

#include <stdio.h>
#include <stdlib.h>
int main() {
    int status = system("ls -l");
    if (status == -1) {
        perror("system call failed");
        exit(EXIT_FAILURE);
    }
    printf("Command execution status: %d\n", status);
    exit(EXIT_SUCCESS);
}
  • system 函数通常与 shell 命令搭配使用,这些命令可以直接在 shell 中执行。例如,你可以使用 system 来执行一个简单的 shell 命令,如 rm;
  • popen 函数则与 shell 命令和管道搭配使用。popen 可以读取或写入 shell 命令的输出或输入。例如,你可以使用 popen 来读取 ls -l 命令的输出;

总结来说,system 函数适合执行简单的 shell 命令,而 popen 函数适合与 shell 命令和管道配合使用,以读取或写入命令的输出或输入。

  • 34
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值