一、标准文件描述符
linux系统会将每个对象当作文件来处理,包括输入和输出。linux用文件描述符来描述每个对象。文件描述符是一个非负整数,唯一会标识的是打开的文件。每个进程一次最多能打开9个文件描述符。处于特殊目的,bash shell保留了前三个文件描述符(0,1,2)。
文件描述符 | 缩写 | 描述 |
---|---|---|
0 | STDIN | 标准输入 |
1 | STDOUT | 标准输出 |
2 | STDERR | 标准错误 |
1.1 STDIN
STDIN文件描述符代表shell的标准输入。对于终端界面来说标准输入就是键盘。shell会从STDIN对应的键盘获取数据并处理。
使用输入重定向时,linux会用重定向指定的文件替换标准输入文件描述符。
许多bash命令可以从STDIN接收数据,例如cat
~$ cat
first line
first line
second line
second line
也可以使用输入重定向强制cat接收来自STDIN之外的文件的数据。
$ cat < test.sh
#!/usr/bin/bash
cat ./test.sh| while read line
do
echo $line
done
1.2 STDOUT
STDOUT文件描述符代表shell的标准输出。在终端界面上标准输出就是显示器。在默认情况下大多数bash命令会将输出送往STDOUT文件描述符。可以使用输出重定向更改此设置。
$ ls -l >file1
$ cat < file1
total 48
...
-rw-rw-r-- 1 ubuntu ubuntu 0 Jun 12 18:03 file1
-rw-rw-r-- 1 ubuntu ubuntu 11 May 24 15:49 file2
...
也可以使用 >> 将数据追加到某个文件。
但是对脚本使用标准输出重定向,就会遇到一个问题,看看下面的例子:
$ ls -al nofile >file3
ls: cannot access 'nofile': No such file or directory
$ cat < file3
$
shell创建了输出重定向,但错误信息依然显示在屏幕上。
shell对于错误信息的处理跟普通输出是分开的。如果想让错误信息输出到文件,需要重定向错误。
1.3 STDERR
shell通过特殊的STDERR文件描述符处理错误信息。STDERR文件描述代表shell的标准错误输出。shell运行或者运行在shell的程序和脚本出错时,生成的错误信息都会送往这个位置。在默认情况下STDOUT和STDERR指向同一个地方,也就是显示器。
1.3.1 只重定向错误
STDERR文件描述符为2,可以将文件描述符值放在重定向符号前,只重定向错误信息。
$ ls -l nofile 2> file3
$ cat < file3
ls: cannot access 'nofile': No such file or directory
1.3.2 重定向错误信息和正常输出
如果想重定向错误和输出信息,必须使用两个重定向符号
$ ls -al file1 nofile 1> file2 2>file3
$ cat <file2
--w--w---- 1 ubuntu ubuntu 0 Jun 12 18:23 file1
$ cat <file3
ls: cannot access 'nofile': No such file or directory
可以使用这种方式区分脚本的正常输出和错误信息。
也可以将STDERR和STDOUT重定向到一个文件,bash shell提供了特殊的重定向符号 &>
$ ls -al file1 nofile &> file2
$ cat < file2
ls: cannot access 'nofile': No such file or directory
--w--w---- 1 ubuntu ubuntu 0 Jun 12 18:23 file1
二、在脚本中重定向输出
2.1 临时重定向
如果你有意在脚本中生成一条错误信息。可以将一行单独的信息重定向到STDERR。这只需要使用输出重定向符号将输出重定向到STDERR文件描述符。在重定向到文件描述符时,必须在文件描述符值前面加一个 &
#!/usr/bin/bash
# test.sh
echo "this a error 1" >&2
echo "this a error 2" >&2
echo "this a error 3" >&2
echo "this is a normal output 1"
echo "this is a normal output 2"
echo "this is a normal output 3"
$ ./test.sh > file2 2> file3
$ cat <file2
this is a normal output 1
this is a normal output 2
this is a normal output 3
$ cat <file3
this a error 1
this a error 2
this a error 3
2.2 永久重定向
如果脚本中有大量数据需要重定向,那么逐条重定向echo语句会很麻烦。这时可以使用exec命令,它告诉shell在脚本执行期间重定向某个特定文件描述符:
#!/usr/bin/bash
exec 1>fileout
echo "this is a normal output 1"
echo "this is a normal output 2"
echo "this is a normal output 3"
$ ./test.sh
$ cat <fileout
this is a normal output 1
this is a normal output 2
this is a normal output 3
三、在脚本中重定向输入
与重定向STDERR和STDOUT相似,可以将STDIN从键盘重定向到指定位置。linux系统中,exec命令可以将STDIN重定向到文件:
#!/usr/bin/bash
exec 0<test.sh
while read opt
do
echo $opt
done
$ ./test.sh
#!/usr/bin/bash
exec 0<test.sh
while read opt
do
echo $opt
done
read命令读取用户输入的数据,将STDIN重定向为文件后,当read试图从STDIN读取数据时,就会到文件中检索数据。
四、创建自己的重定向
重定向输入输出时,并不局限于默认的3个文件描述符。文件描述符3到8均可以用作输入和输出的重定向。
4.1 创建输出文件描述符
可以用exec命令分配用于输出的文件描述符。
#!/usr/bin/bash
exec 3>fileout
echo "this should store in the file" >&3
echo "this is a normal output"
$ ./test.sh
this is a normal output
$ cat <fileout
this should store in the file
4.2 重定向文件描述符
有一种方法可以恢复已重定向的文件描述符。可以先将STDOUT的位置重定向到一个文件描述符,之后再用这个文件描述符恢复STDOUT
#!/usr/bin/bash
exec 3>&1
exec >fileout
echo "store in the fileout 1"
echo "store in the fileout 2"
echo "store in the fileout 3"
exec 1>&3
echo "normal output 1"
echo "normal output 2"
echo "normal output 3"
$ ./test.sh
normal output 1
normal output 2
normal output 3
$ cat < fileout
store in the fileout 1
store in the fileout 2
store in the fileout 3
4.3 创建输入文件描述符
可以采用和重定向输出同样的方法重定向输入文件描述符。在重定向之前先将STDIN的位置保存到另一个文件描述符,之后再用这个文件描述符恢复STDIN。
#!/usr/bin/bash
#test.sh
exec 3<&0
exec 0<test.sh
count=1
while read opt
do
echo $count $opt
count=$[ $count+1 ]
done
exec 0<&3
#在bash中执行脚本
$ ./test.sh
1 #!/usr/bin/bash
2 exec 3<&0
3 exec 0<test.sh
4
5 count=1
6 while read opt
7 do
8 echo $count $opt
9 count=$[ $count+1 ]
10 done
11
12 exec 0<&3
4.4 关闭文件描述符
关闭文件描述符,只需要将文件描述符重定向到 &- 即可。
例: exec 3>&-
五、抑制命令输出
要抑制命令输出,只需将输出重定向到 /dev/null
六、将消息同时送往显示器和文件
有时需要将消息同时发送到文件和显示器,与其使用两次重定向,不如使用特殊命令tee。
tee filename
tee命令:将STDIN的数据同时送往两处。一处是显示器,一处是filename指定的文件。
如果要将数据追加到文件,使用 -a选项。
$ date | tee fileout
Wed 12 Jun 2024 08:09:41 PM CST
ubuntu@VM-8-14-ubuntu:~$ cat <fileout
Wed 12 Jun 2024 08:09:41 PM CST