如何在C语言中调用shell命令
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在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("free>result.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。
参考技术A1、system(执行shell 命令)
相关函数 fork,execve,waitpid,popen
表头文件 #include<stdlib.h>
定义函数 int system(const char * string);
函数说明 system()会调用fork()产生子进程,由子进程来调用/bin/sh-c
string来执行参数string字符串所代表的命令,此命令执行完后随
即返回原调用的进程。在调用system()期间SIGCHLD 信号会被暂时
搁置,SIGINT和SIGQUIT 信号则会被忽略。
返回值 如果system()在调用/bin/sh时失败则返回127,其他失败原因返回-
1。若参数string为空指针(NULL),则返回非零值。如果system()调
用成功则最后会返回执行shell命令后的返回值,但是此返回值也有
可能为system()调用/bin/sh失败所返回的127,因此最好能再检查
errno 来确认执行成功。
附加说明 在编写具有SUID/SGID权限的程序时请勿使用system(),system()会
继承环境变量,通过环境变量可能会造成系统安全的问题。
main()
system(“ls -al /etc/passwd /etc/shadow”);
2、popen(建立管道I/O)
相关函数 pipe,mkfifo,pclose,fork,system,fopen
表头文件 #include<stdio.h>
定义函数 FILE * popen( const char * command,const char * type);
函数说明 popen()会调用fork()产生子进程,然后从子进程中调用/bin/sh -c
来执行参数command的指令。参数type可使用“r”代表读取,“w”
代表写入。依照此type值,popen()会建立管道连到子进程的标准输
出设备或标准输入设备,然后返回一个文件指针。随后进程便可利
用此文件指针来读取子进程的输出设备或是写入到子进程的标准输
入设备中。此外,所有使用文件指针(FILE*)操作的函数也都可以使
用,除了fclose()以外。
返回值 若成功则返回文件指针,否则返回NULL,错误原因存于errno中。
错误代码 EINVAL参数type不合法。
注意事项 在编写具SUID/SGID权限的程序时请尽量避免使用popen(),popen()
会继承环境变量,通过环境变量可能会造成系统安全的问题。
main()
FILE * fp;
char buffer[80];
fp=popen(“cat /etc/passwd”,”r”);
fgets(buffer,sizeof(buffer),fp);
printf(“%s”,buffer);
pclose(fp);
执行 root :x:0 0: root: /root: /bin/bash
3、使用vfork()新建子进程,然后调用exec函数族
#include<unistd.h>main()
char * argv[ ]=“ls”,”-al”,”/etc/passwd”,(char*) ;
if(vfork() = =0)
execv(“/bin/ls”,argv);
else
printf(“This is the parent process\\n”);
参考技术B 可以通过system函数,调用shell命令。
1 函数原型:
int system(const char *cmd);
2 功能:
调用cmd内容的系统命令,即shell命令。
3 头文件:
stdlib.h
4 举例:
system("ls");
打印当前工作目录下的文件。 参考技术C 在linux操作系统中,很多shell命令使用起来非常简单,这些shell命令的程序实现已经被底层实现好。有时候需要在程序中调用shell命令,这样可以就不用在控制台上手动输入shell命令了,下面就以三个函数为例来讲解如何在C语言中调用shell命令。
1、system(执行shell 命令)
相关函数 fork,execve,waitpid,popen
表头文件 #include<stdlib.h>
定义函数 int system(const char * string);
函数说明 system()会调用fork()产生子进程,由子进程来调用/bin/sh-c
string来执行参数string字符串所代表的命令,此命令执行完后随
即返回原调用的进程。在调用system()期间SIGCHLD 信号会被暂时
搁置,SIGINT和SIGQUIT 信号则会被忽略。
返回值 如果system()在调用/bin/sh时失败则返回127,其他失败原因返回-
1。若参数string为空指针(NULL),则返回非零值。如果system()调
用成功则最后会返回执行shell命令后的返回值,但是此返回值也有
可能为system()调用/bin/sh失败所返回的127,因此最好能再检查
errno 来确认执行成功。
附加说明 在编写具有SUID/SGID权限的程序时请勿使用system(),system()会
继承环境变量,通过环境变量可能会造成系统安全的问题。
范例:
#include<stdlib.h>
main()
system(“ls -al /etc/passwd /etc/shadow”);
2、popen(建立管道I/O)
相关函数 pipe,mkfifo,pclose,fork,system,fopen
表头文件 #include<stdio.h>
定义函数 FILE * popen( const char * command,const char * type);
函数说明 popen()会调用fork()产生子进程,然后从子进程中调用/bin/sh -c
来执行参数command的指令。参数type可使用“r”代表读取,“w”
代表写入。
如何在 bash shell 脚本中的 perl 命令调用中使用 shell 变量?
【中文标题】如何在 bash shell 脚本中的 perl 命令调用中使用 shell 变量?【英文标题】:How to use shell variables in perl command call in a bash shell script? 【发布时间】:2012-10-17 02:52:04 【问题描述】:如何在 bash shell 脚本的 perl 命令调用中使用 shell 变量?
我的 shell 脚本中有一个 perl 命令来计算日期 -1。
如何在 perl 命令调用中使用$myDate
?
这是我脚本中的部分:
myDate='10/10/2012'
Dt=$(perl -e 'use POSIX;print strftime '%m/%d/%y', localtime time-86400;")
我想用$myDate
代替%m/%d/%y
。
任何帮助将不胜感激。
谢谢。
【问题讨论】:
用myDate
的值替换'%m/%d/%y'
没有任何意义,除非您将myDate
的值更改为%m/%d/%y
之类的值。请适当地解决您的问题。
【参考方案1】:
来自 shell 的变量在 Perl 的 %ENV
哈希中可用。对于bash
(和其他一些shell),您需要采取额外的步骤“导出”您的shell 变量,以便子进程可以看到它。
mydate=10/10/2012
export mydate
perl -e 'print "my date is $ENVmydate\n"'
【讨论】:
这是一个规则的简单答案。上面的只是看起来像一些我无法理解的复杂代码 另外,如果您运行perl -p
,那么它会将--
解释为文件名,因此只能在此类脚本中使用$ENV
@henley-chiu :公平地对待@ikegami 接受的答案,使用“--arg”方法可以避免污染 bash 环境,而在 bash 函数或别名中使用 export
意味着运行带有export
的函数/别名将导致在 bash 会话期间设置“mydate”。【参考方案2】:
与将值传递给任何其他程序的方式相同:将其作为 arg 传递。 (您可能很想生成 Perl 代码,但这是个坏主意。)
Dt=$( perl -MPOSIX -e'print strftime $ARGV[0], localtime time-86400;' -- "$myDate" )
请注意,代码并不总是返回昨天的日期(因为并非所有日期都有 86400 秒)。为此,你会想要
Dt=$( perl -MPOSIX -e'my @d = localtime time-86400; --$d[4]; print strftime $ARGV[0], @d;' -- "$myDate" )
或
Dt=$( perl -MDateTime -e'print DateTime->today(time_zone => "local")->subtract(days => 1)->strftime($ARGV[0]);' -- "$myDate" )
或者干脆
Dt=$( date --date='1 day ago' +"$myDate" )
【讨论】:
这篇文章假设你想使用myDate
作为你所说的格式说明符,这意味着myDate
实际上包含%m/%d/%y
之类的东西。【参考方案3】:
在 5.24 版本中使用 "
代替 '
也会将 shell 变量传递给 perl。
mydate=22/6/2016
perl -e "print $mydate"
【讨论】:
这是池上在接受的答案中建议反对的,有充分的理由。如果您可以完全控制mydate
并了解您在做什么,那么将其作为 Perl 代码进行插值就可以了……但在这种情况下肯定不是这样,因此这个 sn-p 将产生不稳定的输出 0.00181878306878307
。 【参考方案4】:
为什么不这样:
$ENV'PATH' = $ENV'PATH'.":"."/additional/path";
【讨论】:
【参考方案5】:对我来说,我需要使用$ENV'VARIABLE'
将shell 中的VARIABLE
传递给Perl。我不知道为什么只是 $ENVVARIABLE
不起作用。
例如,
在 Bash 中:
#!/bin/bash -l
VARIABLE=1
export VARIABLE
perl example.pl
在 Perl 中:
#!/usr/bin/perl -w
print "my number is " . $ENV'VARIABLE'
【讨论】:
【参考方案6】:与将值传递给任何其他程序的方式相同:将其作为 arg 传递。 (您可能很想生成 Perl 代码,但这是个坏主意。)
Dt=$( perl -MPOSIX -e'my($m,$d,$y) = split qr/, $ARGV[0]; --$d; print strftime "%m/%d/%y", 0,0,0, $d,$m-1,$y-1900;' -- "$myDate" )
【讨论】:
这篇文章假设你真的想使用myDate
作为修改日期而不是格式说明符。以上是关于如何在C语言中调用shell命令的主要内容,如果未能解决你的问题,请参考以下文章