Shell总结09-IO重定向
重定向作为unix特有的操作,其操作符是shell默认的内置命令
符号 | 模式 |
---|---|
> | 输出重定向覆盖模式 |
>> | 输出重定向追加模式 |
< | 输入重定向覆盖模式 |
<< | 输入重定向追加模式 |
>& | 文件描述符绑定符 |
<> | 读写访问操作符 |
标准stdin、stdout、stderr
IO重定向通常涉及三个基本的文件描述符stdin、stdout、stderr分别对应描述符数值就是0、1、2。操作系统会为每个进程都建立3个标准输入输出描述符,然后映射到当前字符终端tty类型设备上
[root@localhost ~]# ls /dev/std* -l
lrwxrwxrwx. 1 root root 15 Jul 10 23:45 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx. 1 root root 15 Jul 10 23:45 /dev/stdin -> /proc/self/fd/0
lrwxrwxrwx. 1 root root 15 Jul 10 23:45 /dev/stdout -> /proc/self/fd/1
[root@localhost ~]# ls -l /proc/self/fd/
lrwx------. 1 root root 64 Jul 10 23:52 0 -> /dev/pts/0
lrwx------. 1 root root 64 Jul 10 23:52 1 -> /dev/pts/0
lrwx------. 1 root root 64 Jul 10 23:52 2 -> /dev/pts/0
lr-x------. 1 root root 64 Jul 10 23:52 3 -> /proc/3584/fd
输出重定向
#标准输出定向到log.txt
ls 1 > log.txt
ls > log.txt #通常标准输出文件描述符1都会省略
#将 标准错误 定向到error.txt
ls 2 > error.txt
#把 标准输出 和 标准错误 输出重定向到logall.txt文件中
ls &> logall.txt
ls >& logall.txt
ls > logall.txt 2>&1
ls > 2>&1 > logall.txt #只会把标准输出1定向到logall.txt中
#把标准输出和标准错误输出重定向到/dev/null文件中-抛弃标准输出和标准错误
ls > /dev/null 2>&1
#重定向操作符的解释顺序为从左到右依次执行重定向操作
#>&是文件描述符绑定标记,比如N>&M执行会创建或更新 符号链接/proc/self/fd/N 到 符号链接/proc/self/fd/M
输入重定向
输入重定向通常用于捕获来自用户或者文件的stdin标准输入
0< FILENAME
< FILENAME #表示从文件中获得输入
利用输入重定向实现自动yum自动安装
#!/bin/bash
# 实现自动yum自动安装
if [ $# -lt 1 ]; then
echo "Usage: $0 package(s)"
exit 1
fi
while (($#)); do
yum install "$1" < CONFIRM
y
CONFIRM
shift
done
输入和输出重定向可以组合使用
echo 1234567890 > filea
exec 3<> filea # 读写模式打开filea,文件描述符为3
read -n 4 <&3
echo -n . >&3
exec 3>&-
cat filea # 1234.67890
exec命令与|pipe管道重定向
exec命令和pipe管道作为重定向的应用通常使用在各种命令组合的场景。
-
exec
exec 0 < file # 将文件重定向到标准输入(0在碰到<时一般省略) exec < file
- exec输入重定向
#!/bin/bash echo "line1" >> data-file echo "line2" >> data-file exec 6<&0 # 将 标准输入0 和 fd6 绑定,目的是用6保存0的当前状态 exec < data-file # 将data-file读入标准输入 read a1 # read标准输入0(相当于读data-file首行、第二行) read a2 echo $a1 #line1 echo $a2 #line2 exec 0<&6 6<&- #从fd6中还原标准输入0,然后关闭fd6 # <&6 6<&- read b1 #还原了stdin的read功能 echo "b1 = $b1" #键盘输入值 exit 0
- exec输出重定向
#!/bin/bash LOGFILE=logfile.txt exec 6>&1 # 保存stdout到fd6. exec > $LOGFILE # 将stdout定向到LOGFILE # -----------------开始在LOGFILE中记入内容--------------------- # echo -n "Logfile: " date echo "-------------------------------------" echo echo "Output of "ls -al" command" echo ls -al echo; echo echo "Output of "df" command" echo df # -----------------停止在LOGFILE中记入内容--------------------- # # ----------------------------------------------------------- # exec 1>&6 6>&- # 还原stdout到默认的tty终端设备 echo "== stdout now restored to default == " ls -al exit 0
-
Pipeline管道
pipeline相比>更有一般性,搭配多个命令使用可以理解为是链式的>
command1 | command2 | command3 > output-file
cat *.txt | sort | uniq > result-file #将排序去重结果写入result-file
-
exec与pipeline比较
find . -type f -name '*.dmg' -exec echo {}.a ; #有多少个dmg文件exec后命令就执行多少次 find . -type f -name '*.dmg' -print0 |xargs -0 -I -n1 {} echo {}.a find . -type f -name '*.dmg' -exec echo {} + #dmg文件列表作为后续命令的整体参数(效率较高) find . -type f -name '*.dmg' -print0 |xargs -0