重定向

Linux 中标准的输入设备默认指的是键盘,标准输出指的是显示器,而这里的重定向也就是对输入、输出的重定向;

  • 输入重定向:指的是重新指定设备来代替键盘作为新的输入设备;
  • 输出重定向:指的是重新指定设备来代替显示器作为新的输出设备。

通常是用文件或命令的执行结果来代替键盘作为新的输入设备,而新的输出设备通常指的就是文件。

在 Linux 系统中,一切皆是文件,键盘和显示器等硬件都是文件,如下表:

设备 设备文件名 文件描述符 类型
键盘 /dev/stdin 0 标准输入
显示器 /dev/stdout 1 标准输出
显示器 /dev/stderr 2 标准错误输出

从表中可以看出,键盘的设备文件名为 /dev/stdin ,显示器标准正确输入的设备文件名为 /dev/stdout,显示器标准错误输入的设备文件名为 /dev/stderr

这些设备文件名非常不好记忆,Shell 允许我们用文件描述符来描述对应的设备,也就是用 0、1、2,分别对应键盘、正确显示器,错误显示器。

输入重定向

输入重定向所用到的符号如表所示:

命令符号格式 作用
命令 < 文件 将文件作为命令的输入
命令 << 分界符 表示从标准输入设备(键盘)中读入,直到遇到分界符才停止(读入的数据不包括分界符),这里的分界符其实就是自定义的字符串;通常分界符用的最多的是 EOF
命令 < 文件 1 > 文件 2 将文件 1 作为命令的输入设备,该命令的执行结果输出到文件 2 中。

示例:

默认情况下,cat 命令会接受标准输入设备(键盘)的输入,并显示到控制台,但如果用文件代替键盘作为输入设备,那么该命令会以指定的文件作为输入设备,并将文件中的内容读取并显示到控制台。

以 /etc/passwd 文件(存储了系统中所有用户的基本信息)为例,执行如下命令:

1
2
3
4
root@ls529hJ9gm:~# cat /etc/passwd
#这里省略输出信息
root@ls529hJ9gm:~# cat < /etc/passwd
#输出结果同上面命令相同

注意,虽然执行结果相同,但第一行代表是以键盘作为输入设备,而第二行代码是以 /etc/passwd 文件作为输入设备。

示例 2:

1
2
3
4
5
6
7
8
9
## wc -l 命令统计用户输入数据的行数,输入完数据之后再使用 ctrl+d 结束输入
root@ls529hJ9gm:~# wc -l
11
22
2

## 上面我输入了11、22,最终统计输入了2行数据,那这里我使用输入重定向,将默认输入的键盘换到一个文件输入,也是上面的 /etc//passwd 文件
root@ls529hJ9gm:~# wc -l < /etc/passwd
29

最终结果与示例 1 相同,统计出了 29 行。

输出重定向

命令的输出是输出给标准输出的,也就是输出到显示器上。而输出重定向就是命令的输出,不输出给标准输出,而是把输出的内容输出到文件中或者其他的输出设备中。

输出重定向所用到的符号如表所示:

命令符号格式 作用
命令 > 文件 以覆盖的方式,把命令的正确输出,输出到指定的文件或者设备当中
命令 2> 文件 以覆盖的方式,把命令的错误输出,输出到指定的文件或者设备当中
命令 >> 文件 以追加的方式,把命令的正确输出,输出到指定的文件或者设备当中
命令 2>> 文件 以追加的方式,把命令的错误输出,输出到指定的文件或者设备当中
命令 > 文件 2>&1 以覆盖的方式,把命令的正确输出和错误输出,输出到指定的文件或者设备当中
命令 >> 文件 2>>&1 以追加的方式,把命令的正确输出和错误输出,输出到指定的文件或者设备当中
命令 >> 文件 1 2>>文件 2 以追加的方式,把命令的正确输出输出到文件 1,把错误输出输出到文件 2 中

标准输出重定向

1
2
3
4
5
6
7
8
9
# 覆盖的方式
[root@localhost ~]# pwd > abc
[root@localhost ~]# cat abc
/root
# 追加的方式
[root@localhost ~]# pwd >> abc
[root@localhost ~]# cat abc
/root
/root

只要该命令有结果,都能够进行输出重定向。

标准错误输出重定向

1
2
3
4
5
[root@localhost ~]# lsdgagsa 2>> abc
[root@localhost ~]# cat abc
/root
/root
-bash: lsdgagsa: command not found

这个 2 是文件描述符,表示标准错误输出。

1
2
这里需要注意的是,上边的标准正确输出和标准错误输出的重定向有一些小问题,就是我要事先知道这条命令是否报错,才能选择是使用标准正确输出还是使用标准错误输出。
这样十分不合理,我明知道命令会报错,那我直接写对不就完了。所以我们在工作中写脚本的时候,常用的输出重定向的方式是下面的方式。

正确输出和错误输出同时保存

有 3 种方式

方式一

  • 命令 > 文件 2>&1:以覆盖的方式,把正确输出和错误输出都保存到同一个文件当中。
  • 命令 >> 文件 2>&1:以追加的方式,把正确输出和错误输出都保存到同一个文件当中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 把ls命令的查询结果覆盖存储到abc文件中
[root@localhost ~]# ls > abc 2>&1
[root@localhost ~]# cat abc
anaconda-ks.cfg
install.log
install.log.syslog
# 把错误信息追加存储到abc文件中
[root@localhost ~]# lsadfgag >> abc 2>&1
[root@localhost ~]# cat abc
anaconda-ks.cfg
install.log
install.log.syslog
-bash: lsadfgag: command not found

方式二

  • 命令 &> 文件:以覆盖的方式,把正确输出和错误输出都保存到同一个文件当中。
  • 命令 &>> 文件:以追加的方式,把正确输出和错误输出都保存到同一个文件当中。(常用)
1
2
3
4
5
6
7
8
9
# 把pwd命令的结果覆盖存储到abc文件中
[root@localhost ~]# pwd &> abc
[root@localhost ~]# cat abc
/root
# 把错误信息追加存储到abc文件中
[root@localhost ~]# lsadfgag &>> abc
[root@localhost ~]# cat abc
/root
-bash: lsadfgag: command not found

方式三

命令 >> 文件 1 2>>文件 2:把正确的输出追加到文件 1 当中,把错误的输出追加到文件 2 中。(常用)

1
2
3
4
5
6
[root@localhost ~]# pwd >> ok 2>>err
[root@localhost ~]# cat ok
/root
[root@localhost ~]# asdasd >> ok 2>>err
[root@localhost ~]# cat err
-bash: asdasd: command not found
1
注意,在错误输出里,2和`>`和`>>`之间是不能有空格的

这里的方式是选择统一保存呢还是分开保存,全看你个人习惯。

管道符

管道符 |,也是 Shell 命令。

管道符的作用是链接多个命令,把命令 1 的结果作为命令 2 的操作对象。

1
2
命令格式:命令1 | 命令2
命令1的正确输出作为命令2的操作对象

管道符主要用于多重命令处理,前面命令的打印结果作为后面命令的输入。简单点说就是,就像工厂的流水线一样,进行完一道工序后,继续传送给下一道工序处理…

应用

  • 例子 1

举个例子,我们经常需要使用 ls -l 命令查看文件的长格式,不过在有些目录中文件众多,比如 etc/ 目录,使用 ls -l 命令显示的内容就会非常多,只能看到最后的内容,而不能看到前面输出的内容。

这时候可以使用 more 命令,more 命令可以分屏现实文件内容,而不能看到前面输出的内容。

使用管道符,将这 2 个命令链接起来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[root@localhost ~]# ls -l /etc | more
总用量 1160
drwxr-xr-x 4 root root 4096 5月 30 11:12 acpi
-rw-r--r-- 1 root root 2981 5月 30 11:09 adduser.conf
-rw-r--r-- 1 root root 46 8月 29 02:49 adjtime
drwxr-xr-x 3 root root 4096 5月 30 11:11 alsa
drwxr-xr-x 2 root root 4096 10月 14 10:47 alternatives
drwxr-xr-x 3 root root 4096 5月 30 11:13 apm
drwxr-xr-x 5 root root 4096 5月 30 11:15 apparmor.d
-rw-r--r-- 1 root root 73 5月 17 10:34 appstore.json
drwxr-xr-x 7 root root 4096 8月 29 10:48 apt
drwxr-xr-x 3 root root 4096 5月 30 11:15 avahi
-rw-r--r-- 1 root root 1987 8月 4 2020 bash.bashrc
-rw-r--r-- 1 root root 45 2月 12 2019 bash_completion
drwxr-xr-x 2 root root 4096 8月 29 10:53 bash_completion.d
-rw-r--r-- 1 root root 367 3月 17 2022 bindresvport.blacklist
drwxr-xr-x 2 root root 4096 5月 30 11:15 binfmt.d
drwxr-xr-x 2 root root 4096 5月 30 11:14 bluetooth
drwxr-xr-x 3 root root 4096 5月 30 11:14 browser
drwxr-xr-x 3 root root 4096 5月 30 11:09 ca-certificates
-rw-r--r-- 1 root root 5989 5月 30 11:09 ca-certificates.conf
drwxr-xr-x 2 root root 4096 5月 30 11:09 calendar
drwxr-s--- 2 root dip 4096 5月 30 11:14 chatscripts
drwxr-xr-x 2 root root 4096 5月 30 11:14 cracklib
drwxr-xr-x 2 root root 4096 5月 30 11:14 cron.d
drwxr-xr-x 2 root root 4096 5月 30 11:20 cron.daily
drwxr-xr-x 2 root root 4096 5月 30 11:09 cron.hourly
drwxr-xr-x 2 root root 4096 5月 30 11:09 cron.monthly
-rw-r--r-- 1 root root 1042 10月 11 2019 crontab
drwxr-xr-x 2 root root 4096 5月 30 11:09 cron.weekly
drwxr-xr-x 2 root root 4096 5月 30 11:15 cryptsetup-initramfs
--More--

管道符是文本流操作,管道符把前边的 ls -l 命令的结果转换成文本,然后供 more 命令分屏显示。