Chinaunix首页 | 论坛 | 博客
  • 博客访问: 411750
  • 博文数量: 95
  • 博客积分: 5001
  • 博客等级: 大校
  • 技术积分: 1030
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-13 11:43
文章分类

全部博文(95)

文章存档

2007年(95)

我的朋友

分类: LINUX

2007-05-13 12:47:47

练习二:shell编程

 

1.      linux进程

1)进程的概念   

什么是程序,什么是进程呢? 通俗的讲程序是一个包含可以执行代码的文件,是一个静态的文件.而进程是一个开始执行但是还没有结束的程序的实例.就是可执行文件的具体实现. 一个程序可能有许多进程,而每一个进程又可以有许多子进程.依次循环下去,而产生子孙进程. 当程序被系统调用到内存以后,系统会给程序分配一定的资源(内存,设备等等)然后进行一系列的复杂操作,使程序变成进程以供系统调用.在系统里面只有进程没有程序,为了区分各个不同的进程,系统给每一个进程分配了一个ID以便识别. 为了充分的利用资源,系统还对进程区分了不同的状态.进程分为新建,运行,阻塞,就绪和完成五个状态. 新建表示进程正在被创建,运行是进程正在运行,阻塞是进程正在等待某一个事件发生,就绪是表示系统正在等待CPU来执行命令,而完成表示进程已经结束了系统正在回收资源.

2) 进程的创建

 创建一个进程只要调用fork函数就可以了.  

 #include

 pid_t   fork();  

当一个进程调用了fork以后,系统会创建一个子进程.这个子进程和父进程不同的地方只有他的进程ID和父进程ID,其他的都是一样.就象符进程克隆(clone)自己一样.当然创建两个一模一样的进程是没有意义的.为了区分父进程和子进程,我们必须跟踪fork的返回值. fork掉用失败的时候(内存不足或者是用户的最大进程数已到)fork返回-1,否则fork的返回值有重要的作用.对于父进程fork返回子进程的ID,而对于fork子进程返回0.就是根据这个返回值来区分父子进程的. 父进程为什么要创建子进程呢?Linux是一个多用户操作系统,在同一时间会有许多的用户在争夺系统的资源.有时进程为了早一点完成任务就创建子进程来争夺资源. 一旦子进程被创建,父子进程一起从fork处继续执行,相互竞争系统的资源.有时候我们希望子进程继续执行,而父进程阻塞直到子进程完成任务.这个时候可以调用wait或者waitpid系统调用.

 include

 include

 pid_t wait(int *stat_loc);

 pid_t waitpid(pid_t pid,int *stat_loc,int options);

wait系统调用会使父进程阻塞直到一个子进程结束或者是父进程接受到了一个信号.如果没有父进程没有子进程或者他的子进程已经结束了wait回立即返回.成功时(因一个子进程结束)wait将返回子进程的ID,否则返回-1,并设置全局变量errno.stat_loc是子进程的退出状态.子进程调用exit,_exit 或者是return来设置这个值. 为了得到这个值Linux定义了几个宏来测试这个返回值.   

WIFEXITED:判断子进程退出值是非0

WEXITSTATUS:判断子进程的退出值(当子进程退出时非0).

WIFSIGNALED:子进程由于有没有获得的信号而退出.

WTERMSIG:子进程没有获得的信号号(WIFSIGNALED为真时才有意义).

waitpid等待指定的子进程直到子进程返回.如果pid为正值则等待指定的进程(pid).如果为0则等待任何一个组ID和调用者的组ID相同的进程.-1时等同于wait调用.小于-1时等待任何一个组ID等于pid绝对值的进程. stat_locwait的意义一样. options可以决定父进程的状态.可以取两个值

    WNOHANG:父进程立即返回当没有子进程存在时.

    WUNTACHED:当子进程结束时waitpid返回,但是子进程的退出状态不可得到.  

父进程创建子进程后,子进程一般要执行不同的程序.为了调用系统程序,可以使用系统调用exec族调用.exec族调用有着6个函数.  

 include

 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,const char *arg, char * const envp[]);

六个函数的区别:

四个函数-------execlexecvexecleexecve--------第一个参数都是路径名。恶性execvp和恶性eclp的第一个参数则是文件名,如果文件名没有包含“/”,他们会模仿shell的行为搜索$PATH找到要执行的的二进制文件。

三个名字中含有l的函数希望接受以逗号分隔的参数列表,列表以NULL指针作为结束标志,这些参数将传递给被执行的程序。但是,名字中包含v的函数者接受一个向量,也就是指向以空结尾的字符串的指针数组。但如果用带v的函数之一,必须先构造一个argv数组,然后把这个数组传递给exec函数。

最后两个以e结尾的函数-----execveexecle—可以让你为被执行的程序创建专门的环境。这个环境保存在evnp中,他也是一个指向以空结尾的字符串数组指针,数组中每个字符串也是以空结尾。

其他四个函数隐士地通过全局变量environ接受他们的环境。Environ是一个指向字符串数组的指针,数组中包含了调用进程的环境。使用putenvgetenv函数可以操控这些函数继承的环境(见6。)

 

 

2. Linux下文件的操作

1)文件的创建和读写

当要打开一个文件进行读写操作的时候,我们可以使用系统调用函数open.使用完成以后调用另外一个close函数进行关闭操作.

 include

 include

 include

 include  

 int open(const char *pathname,int flags);

 int open(const char *pathname,int flags,mode_t mode);

 int close(int fd);

open函数有两个形式.其中pathname是要打开的文件名(包含路径名称,缺省是认为在当前路径下面).flags可以去下面的一个值或者是几个值的组合.

O_RDONLY:以只读的方式打开文件.

O_WRONLY:以只写的方式打开文件.

O_RDWR:以读写的方式打开文件.

O_APPEND:以追加的方式打开文件.

O_CREAT:创建一个文件.

O_EXEC:如果使用了O_CREAT而且文件已经存在,就会发生一个错误.

O_NOBLOCK:以非阻塞的方式打开一个文件.

O_TRUNC:如果文件已经存在,则删除文件的内容.

如果打开文件成功,open会返回一个文件描述符.我们以后对文件的所有操作就可以对这个文件描述符进行操作了. 当我们操作完成以后,我们要关闭文件了,只要调用close就可以了,其中fd是我们要关闭的文件描述符.

文件打开了以后,我们就要对文件进行读写了.我们可以调用函数readwrite进行文件的读写.

 i nclude

 ssize_t  read(int fd, void *buffer,size_t count);

 ssize_t write(int fd, const void *buffer,size_t count); 

fd是要进行读写操作的文件描述符,buffer是我们要写入文件内容或读出文件内容的内存地址.count是我们要读写的字节数. 

对于普通的文件read从指定的文件(fd)中读取count字节到buffer缓冲区中(必须提供一个足够大的缓冲区),同时返回count. 如果read读到了文件的结尾或者被一个信号所中断,返回值会小于count.如果是由信号中断引起返回,而且没有返回数据,read会返回-1,且设置errnoEINTR.当程序读到了文件结尾的时候,read会返回0. writebuffer中写count字节到文件fd,成功时返回实际所写的字节数. 有时侯要判断文件是否可以进行某种操作(,写等等).这个时候可以使用access函数.  

 include

 int access(const char *pathname,int mode); 

pathname:是文件名称,mode是我们要判断的属性.可以取以下值或者是他们的组合. R_OK文件可以读,W_OK文件可以写,X_OK文件可以执行,F_OK文件存在.当测试成功时函数返回0,否则如果有一个条件不符时,返回-1.

2目录文件的操作

 得到当前的工作路径。

 include

 char *getcwd(char *buffer,size_t size);

 提供一个size大小的buffer,getcwd会把当前的路径考到buffer.如果buffer太小,函数会返回-1和一个错误号.

改变当前目录。

include

Int chdir(char *path );

把当前目录改为path所包含的新目录执行成功返回0,执行失败返回-1并设置errno变量。

 

3.管道文件

系统调用pipe可以创建一个管道.  

 include

 int pipe(int fildes[2]); 

pipe调用可以创建一个管道(通信缓冲区).当调用成功时,可以访问文件描述符fildes[0],fildes[1].其中fildes[0]是用来读的文件描述符,fildes[1]是用来写的文件描述符. 在实际使用中是通过创建一个子进程,然后一个进程写,一个进程读来使用的.

为了实现重定向操作,需要调用另外一个函数dup.

 i nclude

 int dup (int oldfd); 

dup将返回新的文件描述符。程序中应用了以下语句实现重定向。

close( A_to_B[0] );

       close(1);

       dup( A_to_B[1] );.

       传统上,但进程被创建时,该表中的第一个表项指向键盘而另外两个表项指向终端显示器。C运行环境同时内和管理符号stdin,stdout,stderr以使stdin榜定到fileDescripyor[0],stdout绑定到fileDescriptor[1],以及stderr绑定到fileDescriptor[2]所以上面语句意思为:关闭管道的读端,关闭stdout,复制管道写端与进程关联。

 

       4.输出输入的重定向

       同管道操作类似,用了以下代码冲定向输出文件:

       int fid = open( out_file1, O_WRONLY|O_CREAT );//打开文件

       close(1);//关闭stdout

       dup(fid);//fid重定向到进程

       close(fid);//关闭fid

 

       5.关于几个函数

       1#include

pa = getenv("PATH");//查找名为PATH的环境变量并返回指向旗帜的指针

int putenvconst char *string;//添加或改变string中指定的“name=value”对

2#include

       Current_dir = get_current_dir_name(),;//获取当前路径

Login_user = getlogin();//获取登录名

阅读(1674) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~