c语言编写shell命令(c调用shell命令)

今天给各位分享c语言编写shell命令的知识,其中也会对c调用shell命令进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

本文目录一览:

1、如何用c语言写一个shell2、C语言 shell命令3、linux下怎样用c语言调用shell命令4、如何在C语言中调用shell命令5、如何在C语言中执行shell命令

如何用c语言写一个shell

鸟哥是不会有这个的,可以这样想(感觉这样很麻烦,只用一对管道应该也可以,流程也能简单,控制好进程顺序就行。这个编得过):

#include stdio.h

#include stdlib.h

#include string.h

#include fcntl.h

#include unistd.h

#include sys/wait.h

#define CMD_LINE 1024

#define PIPE_MAX 16

#define ARG_MAX 10

typedef struct {

char *arg[ARG_MAX];

char *in;

char *out;

} cmd_t;

extern int parse_token(char *buf, cmd_t cmd[]);

extern int parse(char *buf, cmd_t * cmd);

extern int test_parse(cmd_t cmd[], int len);

int main(int argc, char *argv[])

{

char buf[CMD_LINE];

cmd_t cmd[PIPE_MAX + 1];

int fd[PIPE_MAX][2];

int j, i;

int cmd_len, pipe_len;

pid_t pid;

while (1) {

printf(“my_shell#”);

fgets(buf, CMD_LINE, stdin);

buf[strlen(buf) – 1] = ‘\0’;

cmd_len = parse_token(buf, cmd);

pipe_len = cmd_len – 1;

if (pipe_len PIPE_MAX)

continue;

for (i = 0; i pipe_len; ++i)

pipe(fd[i]);

for (i = 0; i cmd_len; ++i)

if ((pid = fork()) == 0)

break;

if (pid == 0) {

if (pipe_len) {

if (i == 0) {

close(fd[i][0]);

dup2(fd[i][1], 1);

close(fd[i][1]);

for (j = 1; j pipe_len; ++j)

close(fd[j][0]),

close(fd[j][1]);

} else if (i == pipe_len) {

close(fd[i – 1][1]);

dup2(fd[i – 1][0], 0);

close(fd[i – 1][0]);

for (j = 0; j pipe_len – 1; ++j)

close(fd[j][0]),

close(fd[j][1]);

} else {

dup2(fd[i – 1][0], 0);

close(fd[i][0]);

dup2(fd[i][1], 1);

close(fd[i][1]);

for (j = 0; j pipe_len; ++j) {

if ((j != i – 1)

|| (j != i))

close(fd[j][0]),

close(fd[j]

[1]);

}

}

}

if (cmd[i].in) {

int fd = open(cmd[i].in, O_RDONLY);

dup2(fd, STDIN_FILENO);

close(fd);

}

if (cmd[i].out) {

int fd =

open(cmd[i].out,

O_RDWR | O_CREAT | O_TRUNC, 0644);

dup2(fd, STDOUT_FILENO);

close(fd);

}

execvp(cmd[i].arg[0], cmd[i].arg);

fprintf(stderr, “Failed exec\n”);

exit(127);

}

/* parent */

for (i = 0; i pipe_len; ++i)

close(fd[i][0]), close(fd[i][1]);

for (i = 0; i cmd_len; ++i)

wait(NULL);

}

return 0;

}

int parse_token(char *buf, cmd_t cmd[])

{

int n = 0;

#if 1

char *save_p;

char *p = strtok_r(buf, “|”, save_p);

while (p != NULL) {

parse(p, cmd[n++]);

p = strtok_r(NULL, “|”, save_p);

}

#else

cmd[n].arg[0] = “ls”;

cmd[n].arg[1] = “-l”;

cmd[n].arg[2] = NULL;

#endif

return n;

}

int test_parse(cmd_t cmd[], int len)

{

int i;

for (i = 0; i len; ++i) {

printf(“cmd[%d]:”, i);

int j = 0;

while (cmd[i].arg[j])

printf(” %s”, cmd[i].arg[j++]);

if (cmd[i].in)

printf(“\tin:%s”, cmd[i].in);

if (cmd[i].out)

printf(“\tout:%s”, cmd[i].out);

printf(“\n”);

}

return 0;

}

int parse(char *buf, cmd_t * cmd)

{

int i = 0;

cmd-in = NULL;

cmd-out = NULL;

char *p = strtok(buf, ” “);

while (p) {

if (*p == ”) {

if (*(p + 1))

cmd-in = p + 1;

else

cmd-in = strtok(NULL, ” “);

} else if (*p == ”) {

if (*(p + 1))

cmd-out = p + 1;

else

cmd-out = strtok(NULL, ” “);

} else

cmd-arg[i++] = p;

p = strtok(NULL, ” “);

}

cmd-arg[i] = NULL;

return 0;

}

C语言 shell命令

可以通过system函数,调用shell命令。

1 函数原型:

int system(const char *cmd);

2 功能:

调用cmd内容的系统命令,即shell命令。

3 头文件:

stdlib.h

4 举例:

system(“ls”);

打印当前工作目录下的文件。

c语言编写shell命令(c调用shell命令)

linux下怎样用c语言调用shell命令

C程序调用shell脚本共同拥有三种法子 :system()、popen()、exec系列数call_exec1.c ,

system() 不用你自己去产生进程。它已经封装了,直接增加自己的命令

exec 须要你自己 fork 进程,然后exec 自己的命令

popen() 也能够实现运行你的命令,比system 开销小

方法一、system()的使用。我直接上代码吧

int system(const char *command);

我在/home/book/shell新建一个test.sh文件例如以下:

span style=”font-size:18px;”span style=”font-size:18px;”#!bin/bash

echo $HOME

echo “the is test!”/span/span

test.c文件例如以下:

span style=”font-size:18px;”span style=”font-size:18px;”#includestdlib.h

int main()

{

system(“bash /home/book/shell/test.sh”); /* chmod +x test.sh ,路径前面要加上bash */

return 0;

}/span/span

运行例如以下命令来编译:

span style=”font-size:18px;”gcc test.c -o test

/span

测试命令:

span style=”font-size:18px;”./test/span

结果例如以下:

span style=”font-size:18px;”/root

the is test!/span

方法二:popen() 会调用fork()产生 子历程,然后从子历程中调用/bin/sh -c来履行 参数command的指令。参数type可应用 “r”代表读取。“w”代表写入。遵循此type值。popen()会建立 管道连到子历程的标准 输出设备 或标准 输入设备 ,然后返回一个文件指针。

随后历程便可利用 此文件指针来读取子历程的输出设备 或是写入到子历程的标准 输入设备 中。此外,全部应用 文 件指针(FILE*)操作的函数也都能够应用 ,除了fclose()以外。

返回值:若成功 则返回文件指针,否则返回NULL,差错 原因存于errno中。注意:在编写具SUID/SGID权限的程序时请尽量避免应用 popen()。popen()会继承环境变量。通过环境变量可能会造成系统安全的问题

FILE *popen(const char *command, const char *type);

int pclose(FILE *stream);

其它不用改变我们直接改动test.c文件:

#includestdio.h

int main()

{

char buffer[80];

FILE *fp=popen(“bash /home/book/shell/test.sh”,”r”);

fgets(buffer,sizeof(buffer),fp);

printf(“%s”,buffer);

pclose(fp);

return 0;

}

方法三:exec函数簇 (我不太懂,copy别人的。也没有验证。习惯方法一)

须要注意的是exec并非1个函数, 事实上它仅仅是一组函数的统称, 它包含以下6个函数:

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

int execve(const char *path, char *const argv[], char *const envp[];

能够见到这6个函数名字不同, 并且他们用于接受的参数也不同.

实际上他们的功能都是几乎相同的, 由于要用于接受不同的参数所以要用不同的名字区分它们, 毕竟c语言没有函数重载的功能嘛..

可是实际上它们的命名是有规律的:

exec[l or v][p][e]

exec函数里的参数能够分成3个部分, 运行文件部分, 命令参数部分, 环境变量部分.

比如我要运行1个命令 ls -l /home/gateman

运行文件部分就是 “/usr/bin/ls”

命令参赛部分就是 “ls”,”-l”,”/home/gateman”,NULL 见到是以ls开头 每1个空格都必须分开成2个部分, 并且以NULL结尾的啊.

环境变量部分, 这是1个数组,最后的元素必须是NULL 比如 char * env[] = {“PATH=/home/gateman”, “USER=lei”, “STATUS=testing”, NULL};

好了说下命名规则:

e兴许, 参数必须带环境变量部分, 环境变零部分参数会成为运行exec函数期间的环境变量, 比较少用

l 兴许, 命令参数部分必须以”,” 相隔, 最后1个命令参数必须是NULL

v 兴许, 命令参数部分必须是1个以NULL结尾的字符串指针数组的头部指针. 比如char * pstr就是1个字符串的指针, char * pstr[] 就是数组了, 分别指向各个字符串.

关于Linux命令的介绍,看看《linux就该这么学》,具体关于这一章地址3w(dot)linuxprobe/chapter-02(dot)html

p兴许, 运行文件部分能够不带路径, exec函数会在$PATH中找

还有1个注意的是, exec函数会代替运行它的进程, 也就是说, 一旦exec函数运行成功, 它就不会返回了, 进程结束. 可是假设exec函数运行失败, 它会返回失败的信息, 并且进程继续运行后面的代码!

通常exec会放在fork() 函数的子进程部分, 来替代子进程运行啦, 运行成功后子程序就会消失, 可是运行失败的话, 必须用exit()函数来让子进程退出!

如何在C语言中调用shell命令

C语言中调用shell指令,根据调用指令目的,可以区分如下两种情况:

一、需要shell指令执行某一功能,如创建文件夹,或者删除文件夹等,程序中不关注shell指令的输出,那么可以使用system函数。

system函数声明于stdlib.h, 功能为调用系统命令,形式为

int system(const char *cmd);

其中cmd为要执行的命令字符串,返回值为执行是否成功的标记。

比如在Linux下要删除当前文件夹下的所有扩展名为a的文件,即*.a, 可以写作

system(“rm *.a -f”);

二、不仅要执行shell命令,还需要得知运行的打印结果,并在程序中使用。

对于此,有两种方案:

1、用system命令,将输出重定向到一个txt文件中,执行后,再读取txt文件,使用后删除。

比如Linux下获取剩余内存的指令可以写作:

system(“freeresult.txt”);//结果重定向到result.txt中。

FILE *fp = fopen(“result.txt”, “r”);//打开文件。

int r;

while(fgetc(fp) != ‘\n’); //忽略第一行。

fscanf(fp, “%*s%*d%*d%d”,r);//读取第四个域的值,即剩余内存值。

printf(“剩余内存为%d KB\n”,r);//打印结果。

fclose(fp);//关闭文件。

unlink(“result.txt”);//删除临时文件。

2、使用重定向,需要经过磁盘读写,还要删除文件,相对低效。同时还有可能出现临时文件和已有文件重名,导致误删数据的情况。 所以一般使用更方便快捷的方式,即调用popen。

FILE *popen(const char *cmd, const char *mode);

使用popen的功能和system类似,属于方法1中执行命令和打开文件的一个组合。不过这里用到的文件是隐式的,并不会在系统中真正存在。返回的指针即结果文件指针。 当使用pclose关闭后,文件自动销毁。

方法1中的例子,用popen实现如下:

FILE *fp = popen(“free”, “r”);//执行命令,同时创建管道文件。

int r;

while(fgetc(fp) != ‘\n’); //忽略第一行。

fscanf(fp, “%*s%*d%*d%d”,r);//读取第四个域的值,即剩余内存值。

printf(“剩余内存为%d KB\n”,r);//打印结果。

pclose(fp);//关闭并销毁管道文件。

三、注意事项:

虽然调用shell命令有时可以大大减少代码量,甚至有千行代码不如一句shell的说法,不过调用shell命令还是有局限性的:

1、使用shell命令会调用系统资源,效率偏低;

2、不同平台的shell指令不同,导致可移植性下降;

3、调用shell命令时会复制当前进程(fork),如果当前进程的资源占有比较大,会导致瞬间资源占用极大,甚至可能出现失败。

所以,在编码时,除非是测试性的代码,否则在正式代码中不建议使用shell。

如何在C语言中执行shell命令

题主可以使用 exec 系列函数。这系列函数定义在 unistd.h 头文件中,所以使用前请包含这个头文件。这系列函数共有五个,

execl, execlp, execv, execvp, execle

其中常用的是前四个。前四个函数的原型为:

int execl(const char *path, const char *arg, …);

int execlp(const char *file, const char *arg, …);

int execv(const char *path, char *const argv[]);

int execvp(const char *file, char *const argv[]);

这四个函数的主要差别就在于参数的类型和用不用输入命令的绝对路径上。

以路径形式来分,凡是函数名中带 p 的(execlp,execvp)都只需要提供命令的名,函数会自动在当前的环境变量 $PATH 中查找命令的路径。而不带 p 的(execl,execv)必须要提供命令的绝对路径,否则函数会找不到这个命令的位置。这里以 execl 和 execlp 为例,以下运行

ls -l

命令的代码:

#include stdio.h

#include unistd.h

int main() {

    // exec 系列函数出错时会返回 -1,平常返回 0,所以可以

    // 据此来打印错误信息

    // 第一个 ls 是命令的名称,execlp 函数会自动在 $PATH

    // 中寻找这个命令。

    // 后面一个 ls 是要在 shell 中输入的第一个参数

    //(也就是命令名称本身)

    // 使用 NULL 作为参数结尾标记是 exec 系列函数的要求。

    if (execlp(“ls”, “ls”, “-l”, NULL) == -1)

        perror(“Error Executing Command.\n”);

    return 0;

    

}

在 shell 中运行这个 C 程序会输出

和你直接在 shell 中写 ls -l 的效果是一样的。然而,如果你使用不带 p 的 execl, 那么这样写就会报错。

#include stdio.h

#include unistd.h

int main() {

    // execl 只接受命令的绝对路径,所以必须输入完整的

    // 路径 /bin/ls,即

    // if (execl(“/bin/ls”, “ls”, “-l”, NULL) == -1)

    if (execl(“ls”, “ls”, “-l”, NULL) == -1)

        perror(“Error Executing Command.\n”);

    return 0;

    

}

输出结果为:

以参数类型来分,凡是函数名中带 l 的(execl,execlp)都需要把系统命令的参数全部传递给函数,而凡是函数名中带 v 的(execv,execvp)都需要把系统命令的参数统一放在一个数组里,然后把这个数组传递给函数。

比如刚才这个

#include stdio.h

#include unistd.h

int main() {

    if (execlp(“ls”, “ls”, “-l”, NULL) == -1)

        perror(“Error Executing Command.\n”);

    return 0;

    

}

如果改用 execvp 来写的话就是

#include stdio.h

#include unistd.h

int main() {

    // 这个字符串数组存有所有参数(包括命令名本身和

    // 最后的 NULL)

    char * argv[] = {“ls”, “-l”, NULL};

    

    // 这里只需将命令名称和参数数组传递给 execvp 函数即可,

    // 无需将参数一个个传递。同样函数会自动在 $PATH 

    // 中查找命令

    if (execvp(“ls”, argv) == -1)

        perror(“Error Executing Command.\n”);

    return 0;

    

}

运行结果同样和直接写 ls -l 的效果相同。

execv 和 execvp 的区别也在于是否必须输入绝对路径,就不赘述了。

要注意的一点是,如果执行成功,exec 系列函数开启的新进程会完全代替当前的进程,也就是说当前进程会消失。所以一般会将 exec 和 fork 连用,先 fork 出一个子进程,然后在这个子进程中使用 exec 运行别的程序,防止父进程被 exec 覆盖。比如刚才的代码稍微改一下

#include stdio.h

#include unistd.h

int main() {

    char * argv[] = {“ls”, “-l”, NULL};

    if (execvp(“ls”, argv) == -1)

        perror(“Error Executing Command.\n”);

        

    // 加入一个 printf 语句

    printf(“Main process is still running.\n”);

    return 0;

    

}

运行后并不会出现 Main process is still running 这句话,因为 exec 后 main 函数执行产生的进程已经被 ls 命令产生的进程完全覆盖了,所以 exec 函数以下的语句是完全不会执行的。这时就可以使用 fork 来新建一个子进程,在子进程中执行 exec 函数。

#include stdio.h

#include unistd.h

#include sys/types.h

#include sys/wait.h

int main() {

    

    int r;

    

    // fork() 大于零,父进程

    if ((r = fork())  0) {

        int status;

        if (wait(status) != -1) {

            

            // 等待子进程退出

            if(WIFEXITED(status)) {

                printf(“Main process is still running.\n”);

                return 0;

            }

        }

    

    // fork () 等于零,子进程。子进程中运行 exec    

    } else if (r == 0) {

    

        char * argv[] = {“ls”, “-l”, NULL};

        if (execvp(“ls”, argv) == -1)

            perror(“Error Executing Command.\n”);

        return 0;

    

    // fork() 小于零,出错

    } else {

        perror(“Fork”);

    }

    

    return 0;

    

}

这样运行结果就变成了

Main process is still running 这句话就会被输出到屏幕上。

c语言编写shell命令的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于c调用shell命令、c语言编写shell命令的信息别忘了在本站进行查找喔。

本文来自投稿,不代表【】观点,发布者:【

本文地址: ,如若转载,请注明出处!

举报投诉邮箱:253000106@qq.com

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2024年4月1日 23:57:48
下一篇 2024年4月2日 00:07:05

相关推荐

  • c语言改写模式,c语言实现修改功能

    c语言程序修改? 1、这个程序有4个错误,我都加粗了,第一个是m没有赋初值,第二个是while表达式中的ch=getchar()需要括号括起来,第三个是m=m*10+ch-0中的0也需要用单引号括起来,第四个是第2个while中为m!=0。 2、define容易造成误会,因为不符合一般的编程习惯,false 0, true 1;scanf放在你的那个地方是达…

    2024年5月23日
    4100
  • c语言控制代码的换码序列,c语言交换代码

    求C语言编程大神解答一下下面这个编程代码? k==5,用5去除125余0,所以r=125%5中r为0。由于!0为1,所以执行while循环体:先打印出5(k的值),再n=n/k==125/5=25;由于251则再打印出*号。这一循环结果输出是5*。 下面是我的代码,三个函数分别对应三个问题。 在实现基本要求的前提下,拓展了可以从键盘输入的功能,以下为各题代码…

    2024年5月23日
    5800
  • c语言扫描io脚状态,c语言端口扫描

    求51单片机的上升沿和下降沿C语言检测程序列子,端口就是普通IO口。 上升沿触发是当信号有上升沿时的开关动作,当电位由低变高而触发输出变化的就叫上升沿触发。也就是当测到的信号电位是从低到高也就是上升时就触发,叫做上升沿触发。 单片机怎么计算1s内下降沿的个数的C语言程序或者计算两个下降沿的时间(检测脉冲频率)计算1s内下降沿的个数方法是,一个定时器设置定时1…

    2024年5月23日
    4500
  • c语言mallloc使用的简单介绍

    C语言中使用malloc必须加#includemallo.h? 1、在C语言中使用malloc函数进行动态内存分配。malloc的全称是memory allocation,中文叫动态内存分配。原型:extern void malloc(unsigned int num_bytes);功能:分配长度为num_bytes字节的内存块。 2、你可以看一下C语言那本…

    2024年5月23日
    4500
  • c语言三位小数,C语言三位小数

    怎样用C++语言输出精确到小数点后三位的数? 1、用C++语言输出精确到小数点后三位的数,可以参考下面给出的代码:coutsetiosflags(ios:fixed)setprecision(3)。其中 setiosflags中set是设置的意思。ios是iostream的缩写,即输入输出流。flags是标志的意思。 2、要精确到小数点后若干位,则数据类型为…

    2024年5月23日
    7500
  • c语言21点游戏,二十一点游戏代码c语言

    如何使用C语言编写简单小游戏? 1、数学知识:长方形的面积S=a*b 长方形周长L=2*(a+b)其中a b分别为长方形的宽和高。算法分析:长方形面积及周长均依赖于宽和高,所以先要输入宽高值,然后根据公式计算,输出结果即可。 2、/*也不知道你是什么级别的,我是一个新手,刚接触编程语言,以下是我自己变得一个小程序,在所有c语言的编译器(vc++0、turbo…

    2024年5月23日
    6500
  • c语言当中的null,C语言当中的符号

    C/C++中,NULL和null的区别是什么? nul 和 null要看编译器,不同的编译器有所区别。 所以C或者C++中都使用一个特殊定义NULL表示无效值,其本质就是未定义具体数据类型的0值。 null是是什么都没有的意思。在java中表示空对象。 本意是“空的;元素只有零的”意思。计算机中通常表示空值,无结果,或是空集合。\x0d\x0a在ASCII码…

    2024年5月23日
    4700
  • 包含c语言对txt文件命名的词条

    如何在C语言编程里面修改源文件名字 如果你是在WINDOWS的话,简单了,随便用个编辑器,比如记事本,然后写c源程序,保存到你想要保存的位置。如果你在DOS下,可以用edit,写好以后,按alt键,选择文件菜单,然后保存。 用open打开文件,注意操作模式使用“修改”或者“添加” 用write或者fprintf向文件中写入你的内容。 用close关闭文件。 …

    2024年5月23日
    5000
  • 学c语言编程,学c语言编程用什么软件

    编程开发必须要学C语言吗? 1、要学习。编程开发的学习内容主要包括c语言、python和c+语言。C语言作为一种简单灵活的高级编程语言,它是一个面向过程的语言,一般是作为计算机专业的基础入门语言课程。 2、C语言。对于刚接触编程的人来说,先学习C语言是非常重要的。C语言可以说是是计算机编程语言的鼻祖,其他的编程语言几乎全是由C语言变化衍生出来的。 3、不需要…

    2024年5月23日
    3500
  • c语言用string定义字符串,c语言中用string类型来处理字符串类型

    C++怎样定义定义字符串 1、第一是字符数组来表示字符串。用下面的语句声明:char a[10];C语言中字符数组与字符串的唯一区别是字符串末尾有一个结束符\0,而字符数组不需要。 2、在C中定义字符串有下列几种形式:字符串常量,char数组,char指针 字符串常量 即:位于一对双括号中的任何字符。双引号里的字符加上编译器自动提供的结束标志\0字符,作为 …

    2024年5月23日
    4500

发表回复

登录后才能评论



关注微信