标准I/O和重新定向
当shell启动,它继承三个文件:stdin,stdout和stderr。标准输入通常来自键盘。标准输出和标准错误通常是屏幕。但是很多时候你也许想从文件中读取输入或者把输出保存在文件中。这个时候你就可以使用I/O重新定向,见下表
重新定向操作符表
重新定向操作符 | 作用 |
---|---|
< | 重新定向输入 |
> | 重新定向输出 |
>> | 追加输出 |
2> | 重定向错误 |
&> | 重定向错误和输出,使它们指向同一个数据流向 |
>& | 重定向错误和输出,是它们指向同一个数据流向 |
2>&1 | 重定向错误到标准输出 |
1>&2 | 重定向标准输出到标准错误 |
>| | 重定向输出的时候覆盖noclobber |
<>filename | 如果是一个文件,就把这个文件作为标准输入和标准输出 |
$ tr \'[A-Z]\' \'[a-z]\' < myfile# 将myfile文件的内容重定向输入到tr命令,然后tr将所有大写字母转为小写字母显示到屏幕$ ls > lsfile# 将ls命令输出的结果重定向到文件lsfile中$ date >> lsfile# 将命令date的输出结果追加到文件lsfile中$ dates 2> errfile# dates命令不存在,因此错误消息会被重定向到errfile文件中$ find . -name \'*.txt\' -print > foundit 2> /dev/null$ find . -name \\*.txt -print > foundit 2> /dev/null# 这两种写法结果一样,需要注意的是需要对*进行转义$ find . -name \'*.txt\' -print >& foundit$ find . -name \'*.txt\' -print > foundit 2>&1# 以上两种写法结果一样,都是将标准输出和标准错误输出到同一个文件中$ echo \"File needs an argument\" 1>&2# 将标准输出重定向到标准错误, 该信息标准错误与标准输出合并在一起
exec和重定向
exec命令可以替换当前程序而不需要启动一个新的进程。exec可以改变标准输入和输出而不需要启动一个新的子进程。如果文件用exec打开,read命令就会把文件指针每次向下一行直到文件的末尾。如果要重新从文件开始阅读则必须把文件关闭再重新打开。但是,如果使用linux的cat或者sort工具,操作系统在每一个命令结束后都会将文件关闭一次。
exec命令
exec命令 | 作用 |
---|---|
exec ls | 在shell内执行,当命令ls结束后,直接关闭shell进程 |
exec <filea | 将filea作为标准输入源 |
exec >filex | 将标准输出定向到filex中 |
exec 3<datfile | 将datfile文件输入定向到文件描述符3 |
sort <&3 | 对datfile重定向输入的内容进行分类 |
exec 4>newfile | 将文件描述符4重新定向到newfile |
ls >&4 | ls的输出被重新定向到newfile |
exec 5<&4 | 创建文件描述符4的拷贝文件描述符5 |
exec 3<&- | 关闭文件描述符3 |
$ exec date# 执行完date以后退出shell,如果在登录shell中,那么执行完命令后退出登录,如果在交互窗口中运行,那么将会退出窗口$ exec > temp$ ls$ pwd$ echo hello# 以上输出都被重定向到文件tmp中$ exec > /dev/tty# 再次把标准输出重定向到终端$ echo hello# 标准输出被显示在屏幕上
$ exec 3>files# 在当前shell,将文件描述符3分配给files,并打开作为输出的重定向$ who >&3# 在当前shell,将who的输出输出到files中$ date >&3# 在当前shell,将date的输出重定向到文件描述符3,而此时fd3指向files,因此输出会被输出到files中$ exec 3>&-# 关闭文件描述符3$ exec <files# 在当前shell,将files作为标准输入源,也就是将标准输入重定向到files$ exec <&3# 在当前shell,创建一个标准输入的拷贝fd3$ exec 3<&-# 关闭文件描述符3$ date >&3# 报错,因为文件描述3没有重定向到任何地方
管道
管道就是把管道符号左边命令的输出发送给管道符号右边的命令作为输入。一个管道线可以由不止一个管道组成。
$ who | wc -l$ du .. | sort -n | sed -n \'$p\'# 输出当前目录的上层目录,每一个目录所占用的磁盘块个数通过管道输入到sort来进行排序,然后作为sed命令的输入,打印最后一行$ (du / | sort -n | sed -n \'$p\') 2>/dev/null# 如果因为权限原因无法访问一些目录,du命令将把错误信息发送到stderr,也就是屏幕。当你把整行的命令放在括号中,所有的输出都显示在屏幕上,而所有的错误信息都将送到/dev/null
here文档和重新定向输入
here文档是一种特殊形式的引用。它为需要输出的程序的,例如mail,sort和cat接收在线文本,直到遇到用户定义的结束符号为止。它通常用在shell脚本中创建菜单。需要获得输入的命令后面有<<符号,以及用户定义的结束符号,最后是换行符。下一行就将是被发送给命令的文本。当用户定义的结束符单独出现在行的最左边时,输入就结束了。结束符用来代替Control-D来结束程序的输入。
在命令行上,结束符前<<,制表符或者只有制表符。
$ cat << FINISH> Hello world # 按下回车会出现次级提示符> I can not wait to see u!FINISH # 结束符前后不允许有空格
如果想要允许最后一个结束符前面有一个或多个空格,需要在开始的<<符号后面加上一个短横杠。
cat <<- FINISHhello worldi can find u!FINISH# 这种情况在命令行下有问题,但是在脚本里面可以正常运行