2009年3月19日星期四

[转]在程序中执行UNIX命令或者其它程序

搜狐社区-论坛-聊天室-博客-BBS: "第二章:在程序中执行UNIX命令或者其它程序
在UNIX下,像DOS的command.com那样的程序,我们称之为外壳(shell)。外壳就是一个命令解释器,你在外壳的提示符下输入命令(如同DOS的提示符一样),系统便会执行。
DOS的提示符一般是C:>,当然,你想改成什么样就能改成什么样,又当然,像BBS一样贴张图上去是不太现实的。
UNIX的提示符根据外壳的不同是不同的。
为了更好地说明本章想讲解的内容,我们先做一个外壳试试(玩具级别的)。我们给他起名叫SSH(Sohu Shell)吧。想取名叫CSH,可惜CSH在没生我之前就有了。呵呵。

/* 简单的外壳程序 */
#include<stdio.h>
int main()
{
static char prompt[64]='> ';
char command[256];
int st;

fprintf(stderr,'%s',prompt); // 在屏幕上输出提示符
while(gets(command)!=NULL) // 取得命令
{
if(fork()==0) // 生成子进程
{ // 这里是子进程接下来要做的事
if( execl(command,command,(char *)0)==(-1) )
// 上一句是执行命令
exit(1); // 当出错时子进程异常中止
}
else
{ // 父进程
wait(&st); // 等待子进程结束
fprintf(stderr,'%s',prompt);
// 输出提示符,等待命令
}
}
return 0;
}

执行方法:
%./ssh
>/bin/ls
当前目录下文件名一览
>Ctrl+D
%

普通的外壳在执行exit命令后会关闭。也就是说,退出一层外壳。咱们这个程序现在还做不到。愿意的话加上这个功能试试好了。所以要关闭这个外壳就得来点狠的。Ctrl+D,Ctrl+C什么的。再不你就再开一个外壳然后ps -ef再kill。再狠一些……拆硬盘,拨电源

我们这里有了一个新的函数:execl()。其实他是一组函数中的一个。这组函数如下:
int execl( path , arg0 , arg1 , ... , argn , (char *)0 );
int execv( path , argv );
int execle( path , arg0 , arg1 , ... , argn , (char *)0 , envp );
int execve( path , argv , envp );
int execlp( file , arg0 , arg1 , ... , argn , (char *)0 );
int execvp( file , argv );
其中的参数定义如下:
char *path;
char *file;
char *arg0 , *arg1 , ... , *argn;
char *argv[];
char *envp[];
返回值: 成功时:所执行的命令将会覆盖现有的进程,所以无返回值
失败时:-1
用过TC的朋友应该知道,TC的Process.h里有一个system()函数。这组函数其实和system()的功能差不多。

比方说:
execl( '/bin/ls' , '/bin/ls' , '-al' , '/home' , (char *)0 );
或者
char *argv[];
strcpy( argv[0] , '/bin/ls' );
strcpy( argv[1] , '-al' );
strcop( argv[2] , '/home' );
execv( '/bin/ls' , argv );
都相当于在命令行下敲入了'/bin/ls -al /home'并且回车。(引号不是命令里的。是我解释时加上去的。别看混了)。
execle()和execve(),函数名最后一个字母都是e。就是说,这两个函数在调用其它程序的同时,还可以把环境变量一起传给被调程序
execlp()和execvp(),函数名最后一个字母都是p,就是说,这两个函数在使用的时候,就算你不指定命令文件所在的路径,它也会根据环境变量PATH去挨个地方找。找着就执行。找不着拉倒。
比方说:
setenv $path = ( /bin $path ) 这句话将环境变量PATH的第一个路径设为/bin。这是在SHELL下执行的。C里没这东西吧。
在程序中这样用这个函数
execlp( 'ls' , 'ls' , '-al' , '/home' , (char *)0 );
与上面的效果一样。当然。如果你PATH变量没设好的话。它就不一定找到哪儿去了。

还有一个函数是wait(),说明如下:
#include <sys/types.h>
pid_t wait(int *stat_loc);
返回值就是一个PID了。忘了PID是什么意思的朋友光顾一下我上一篇贴子。
它的参数有些意思。其实它与你的子进程用什么方式结束有关系。当你的子进程以exit()方式结束的话,stat_loc所指向的地址的前8位将会是exit()的参数的后8位,而stat_loc所指向的地址的后8位是0。比方说:你的子进程是exit(1);那stat_loc所指向的地址的内容应该是0000 0001 0000 0000。

exit():
#include <stdlib.h>
void exit(int status);
就算你在程序中没写exit()函数,编译器也是认为你是在最后加入了这个函数。"

没有评论: