shell之输入输出重定向

1.shell的简介:

     (1) 在计算机科学中,Shell俗称壳(用来区别于核),是指“提供使用者使用界面”的软件(命令解析器)。

它类似于DOS下的和后来的cmd.exe。它接收用户命令,然后调用相应的应用程序。Shell既是一种命令语言,又是

一种程序设计语言。作为命令语言,它交互式解释和执行用户输入的命令或者自动地解释和执行预先设定好的一连串

的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和

分支。  在排序算法中,Shell是希尔排序的名称。 传统意义上的shell指的是命令行式的shell,以后如果不特别注

明,shell是指命令行式的shell。

  文字操作系统与外部最主要的接口就叫做shell。shell是操作系统最外面的一层。shell管理你与操作系统之间的

互:等待你输入,向操作系统解释你的输入,并且处理各种各样的操作系统的输出结果。shell提供了你与操作

间通讯的方式。这种通讯可以以交互方式(从键盘输入,并且可以立即得到响应),或者以shell script(非

互)方式执行。shell script是放在文件中的一串shell和操作系统命令,它们可以被重复使用。本质上,shell 

script是命令行命令简单的组合到一个文件里面。Shell脚本和编程语言很相似,也有变量和流程控制语句,但

Shell脚本是解释执行的,不需要编译,Shell程序从脚本中一行一行读取并执行这些命令,相当于一个用户把脚本

中的命令一行一行敲到Shell提示符下执行。


Shell有两种执行命令的方式:

  • 交互式(Interactive):解释执行用户的命令,用户输入一条命令,Shell就解释执行一条。
  • 批处理(Batch):用户事先写一个Shell脚本(Script),其中有很多条命令,让Shell一次把这些命令执行完,而不必一条一条地敲命令。

交互式模式就是shell等待你的输入,并且执行你提交的命令。这种模式被称作交互式是因为shell与用户进行交

互。这种模式也是大多数用户非常熟悉的:登录、执行一些命令、签退。当你签退后,shell也终止了。shell也可

以运行在另外一种模式:批处理(非交互式)模式。在这种模式下,shell不与你进行交互,而是读取存放在文件

中的命令,并且执行它们。当它读到文件的结尾,shell也就终止了。

(2)命令描述

shell 命令重新初始化用户的登录会话。当给出该命令时,就会重新设置进程的控制终端的端口特征,并取消对端

口的所有访问。然后 shell 命令为用户把进程凭证和环境重新设置为缺省值,并执行用户的初始程序。根据调用进

程的登录用户标识建立所有的凭证和环境。

注:shell 命令不会重新设置用户的登录标识

安全性

访问控制:该命令应该被 setuid 为 root 用户,以重新设置用户的进程凭证、授权执行(x)访问所有用户。该命

令应该具有可信计算库属性。

(3)说明

如果Shell 函数成功地执行了所要执行的文件,则它会返回程序的任务 ID。任务 ID 是一个唯一的数值,用来指明

正在运行的程序。如果 Shell 函数不能打开命名的程序,则会产生错误。

注意 缺省情况下,Shell 函数是以异步方式来执行其它程序的。也就是说,用Shell 启动的程序可能还没有完成执

行过程,就已经执行到 Shell 函数之后的语句。

2.重定向

     Linux重定向以前就提及过,现在在简单介绍一下,它是指修改原来默认的一些东西,对原来系统命令的默认执行方式进行改变,比如说简单的我不想看到在显示器的输出而是希望输出到某一文件中就可以通过Linux重定向来进行这项工作。Linux默认输入是键盘,输出是显示器。你可以用重定向来改变这些设置。比如用wc命令的时候本来是要手动输入一篇文字来计算字符数的,用了重定向后可以直接把一个已经写好的文件用‘<’指向这条命令,就直接可以统计这个文件的字符数等了。输出也是一样,你可以把屏幕输出重定向到一个文件里,再到文件里去看结果。重定向操作符可以用来将命令输入和输出数据流从默认位置重定向到其他位置,其输入或输出数据流的位置称为句柄;常见的句柄有三种,当然句柄可以自行扩展,一般的OS都提供类似的功能。句柄 句柄代号 句柄描述

STDIN 0 键盘输入

STDOUT 1 输出信息到提示符窗口

STDERR 2 输出错误信息到提示符窗口


3、用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。
  以下有六种以exec开头的函数,统称exec函数
#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[]);

这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回,如果调用出错则
返回-1, 所以exec函数只有出错的返回值而没有成功的返回值。
说明:
1)不带字母p (表示path)的exec函数 第一个参数必须是程序的相对路径或绝对路径,例如"/bin/ls"或"./a.out",而不能 是"ls"或"a.out"。对于带字母p的函数: 如果参数中包含/,则将其视为路径名。 否则视为不带路径的程序名,在PATH环境变量的目录列表中搜索这个程序。
2)带有字母l( 表示list)的exec函数要求将新程序的每个命令行参数都当作一个参数传给它,命令行 参数的个数是可变的,因此函数原型中有...,...中的最后一个可变参数应该是NULL, 起sentinel的作用。
3)带有字母v( 表示vector)的函数,则应该先构造一个指向各参数的指针数 组,然后将该数组的首地址当作参数传给它,数组中的最后一个指针也应该是NULL,就像main函数 的argv参数或者环境变量表一样。
4)对于以e (表示environment)结尾的exec函数,可以把一份新的环境变量表传给它,其他exec函数 仍使用当前的环境变量表执行新程序。
exec调用举例如下:

char* cons ps_argv[]={"ps","-o","pid,ppid,pgrp,session,tpgid,comm",NULL};

char * const ps_envp[]={"PATH=/bin/usr/bin","TERM=console",NULL};

execl("/bin/ps","ps","-o","pid,ppid,pgrp,session,tpgid,comm",NULL);

execv("/bin/ps",ps_argv);

execle("/bin/ps","ps","-o","pid,ppid,pgrp,session,tpgid,comm",NULL,ps_envp);

execv("/bin/ps",ps_argv,ps_envp);

execlp("ps","ps","-o","pid,ppid,pgrp,session,tpgid,comm",NULL);

execvp("ps",ps_argv);

事实上,只有execve是真正的系统调用,其它五个函数最终都调用execve.

代码实现:


shell之输入输出重定向shell之输入输出重定向shell之输入输出重定向


看一下运行的结果:

shell之输入输出重定向