shel之文件描述符与重定向

文件描述符是与输入和输出流相关联的整数,最广为人知的文件描述符是标准输入(stdin)、标准输出(stdout)和标准错误
(stderr)。默认情况下,正常输出(stdout)和错误信息(stderr)都会显示在屏幕上。脚本可以使用大于号将输出重定向到文件中。

文件描述符

文件描述符是与某个打开的文件或数据流相关联的整数。文件描述符0、1以及2是系统预留的。

  • 0 —— stdin (标准输入)。
  • 1 —— stdout(标准输出)。
  • 2 —— stderr(标准错误)。
$ cat /dev/stdin

将/dev/stdin作为输出文件名来代替stdin,/dev/stderr代表标准错误,
/dev/stdout代表标准输出。这些特殊的设备文件分别对应stdin、stderr和stdout

将一个命令的输入发送给另一个命令

Unix shell脚本可以轻松地将多个命令组合起来生成输出。一个命令的输出可以作为另一个命令的输入。

命令输入通常来自于stdin或参数。输出可以发送给stdout或stderr。当我们组合多个命令时,通常将stdin用于输入,stdout用于输出

在这种情况下,这些命令被称为过滤器(filter)。

  • 方法1:使用管道
    我们使用管道(pipe)连接每个过滤器,管道操作符是|。

cmd1 | cmd2 | cmd3

cmd1的输出传递给cmd2,cmd2的输出传递给cmd3,最终的输出(来自cmd3)会出现在显示器中或被导入某个文件

$ ls | cat -n > out.txt #ls(列出当前目录内容)的输出被传给cat -n,后者为通过stdin所接收到的输入内容加上行号,然后将输出重定向到文件out.txt
  • 方法2:将命令序列的输出赋给变量
  • 子shell法:cmd_output=$(COMMANDS)
$ cmd_output=$(ls | cat -n) 
$ echo $cmd_output 
  • 反标记:cmd_output=COMMANDS
$ cmd_output=`ls | cat -n` 
$ echo $cmd_output 

备注:子shell法的用法

  1. 将一个命令的输入发送给另一个命令
  2. 利用子shell生成一个独立的进程利用子shell生成一个独立的进程
    子shell本身就是独立的进程,因此可以使用()操作符来定义一个子shell。当命令在子shell中执行时,不会对当前shell造成任何影响;所有的改变仅限于该子shell内。
$ pwd
/home/ocean/workspaces/shell
$ (cd /bin; ls)
bash          dir            lessecho    nisdomainname  red 
$ pwd
/home/ocean/workspaces/shell

重定向stdin

$ sudo echo "echo 重定向stdin" > file

(1)< 从文件中读取内容

$ bash < file // 将文件重定向到命令
重定向stdin

重定向stdout

将输出文件重定向到一个文本中【追加/截断】

  • ">"表示将文本保存到文件中,如果文件中已经有了内容,>会先清空内容再添加。
  • ">>"表示文本追加
$ cat temp.txt
cat: temp.txt: No such file or directory
$ echo "This is a sample text 1" > temp.txt 
$ cat temp.txt
This is a sample text 1
$ echo "This is sample text 2" >> temp.txt 
$ cat temp.txt
This is a sample text 1
This is sample text 2
$ echo "This is a sample text 1" > temp.txt 
$ cat temp.txt
This is a sample text 1

重定向操作符(>和>)可以将输出发送到文件中,而不是终端。

  • “>”和>>两者都可以将文本重定向到文件,但是前者会先清空文件,然后再写入内容,而后者会将内容追加到现有文件的尾部
  • 默认情况下,重定向操作符针对标准输出

处理错误时,来自stderr的输出被倾倒入/dev/null中。/dev/null是一个特殊的设备文件,它会丢弃接收到的任何数据。null设备通常也被称为黑洞,因为凡是进入其中的数据都将一去不返。

如果你不想看到或保存错误信息,那么可以将stderr的输出重定向到/dev/null,保证一切都会被清除得干干净净。

重定向stderr

当一个命令发生错误并退回时,它会返回一个非0的退出状态;而当命令成功完成后,它会返回为0的退出状态。退出状态可以从特殊变量$?中获得(在命令结束之后立刻运行echo $?,就可以打印出退出状态)。

$   ls + 
ls: cannot access '+': No such file or directory
$ echo $?
2

stderr会默认输出到品目上
使用>重定向stderr到文本

$ ls + > out.txt   # 定位失败
ls: cannot access '+': No such file or directory
$ cat out.txt
$ ls + 2> out.txt  # 定位成功
$ cat out.txt
ls: cannot access '+': No such file or directory

重定向stderr和stdout

$ echo A1 > a1
$ echo A2 > a2
$ echo A3 > a3
$  chmod 000 a1 #清除所有权限
$ cat a*
cat: a1: Permission denied  #属于stderr信息
A2
A3

(1)stderr重定向到一个文件中,同时将stdout信息发送到终端。

$  cat a* 2> err.txt # stderr被重定向到err.txt 
A2
A3
$ cat err.txt 
cat: a1: Permission denied

(2) 将stdout和stderr重定向到两个不同的文件中

$ cat a* 2> stderr.txt 1>stdout.txt
$ cat stderr.txt 
cat: a1: Permission denied
$ cat stdout.txt 
A2
A3

备注:

>等同于1>
>>等同于1>>

(3) stdout和stderr重定向到同一个文件中

$ cat a* &> alloutput.txt
$ cat alloutput.txt 
cat: a1: Permission denied
A2
A3

stdout是单数据流,可以被重定向到文件或者通过管道传入其他程序。但是无法同时重定向到文件和传入其他程序

(4)想要将数据重定向到文件,并且提供一份重定向数据的副本作为管道中后续命令的stdin:

  • command | tee FILE1 FILE2 | otherCommand
$ cat a* | tee out.txt | cat -n  
 # cat -n 命令 接收stdin中的数据并加上行号然后写入stdout
cat: a1: Permission denied
     1	A2
     2	A3
$ cat out.txt 
A2
A3
  • tee -a
默认情况下,tee会将文件覆盖,但是tee -a可以追加
$  cat a* | tee out.txt | cat -n  
cat: a1: Permission denied
     1	A2
     2	A3
$ cat out.txt 
A2
A3
$ cat a* | tee -a out.txt | cat -n
cat: a1: Permission denied
     1	A2
     2	A3
$ cat out.txt 
A2
A3
A2
A3

自定义文件描述符

文件描述符是一种用于访问文件的抽象指示器。存取文件离不开被称为“文件描述符”的特殊数字。0,1,2是系统保留的
exec命令创建全新的文件描述符。

(1) 创建一个用于读取文件的文件描述符【一次性消耗品】
<:将文件读入stdin

$ echo this is a test line > input.txt 
$ exec 3<input.txt #使用文件描述符3打开并读取文件, 3这个文件描述符只能使用一次
$ cat<&3
this is a test line
$ cat<&3 #如果要再次读取,我们就不能继续使用文件描述符3了[因为stdin是单向数据流],而是需要用exec重新创建一个新的文件描述符3/4/5/6  。
$ cat input.txt 
this is a test line

(2)创建一个用于写入(截断也就是清空模式)的文件描述符
“>”:将文件截断写入 failure

(3)创建一个用于写入(追加模式)的文件描述符

$  exec 5>>input.txt 
$  echo appended line >&5 
$ cat input.txt 
appended line
$ echo appended line >&5 
$ cat input.txt 
appended line
appended line

参考:<Linux_Shell脚本攻略>

猜你喜欢

转载自blog.csdn.net/zhizhengguan/article/details/88310037