shell中的 2>&1含义

在平常项目中,我们经常可以看到如下的shell命令:

* * * * * php /path-to-your-project/artisan schedule:run >> /dev/null 2>&1

前面的命令含义我们都明白,但是后面的 >> /dev/null 2>&1却不太明白,现在就来探讨一下这个命令的含义。

/dev/null

/dev/null(或称空设备)在类Unix系统中是一个特殊的设备文件,它丢弃一切写入其中的数据(但报告写入操作成功),读取它则会立即得到一个EOF[1]

上面这句话摘抄自维基百科。

简单来说,/dev/null就是一个垃圾桶,任何投向这个文件的东西都会被丢弃。所以我们可以将不需要保存的任何输出都可以丢到这里面。

2>&1

理解这个命令的含义之前,我们需要先理解一下在类Unix系统下,每个程序运行后,都会至少打开三个文件描述符。

  • 0:标准输入(stdin)
  • 1:标准输出(stdout)
  • 2:错误输入(stderr)

假如我们有一个shell脚本如下:

1
2
3
4
5
6
7
8
9
#!/bin/bash
date #打印当前时间
while true #死循环
do
#每隔2秒打印一次
sleep 2
whatthis #不存在的命令
echo -e "std output"
done

上续脚本运行的时候,会抛出异常,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Tue Aug 24 09:44:50 CST 2021
./test.sh: line 7: whatthis: command not found
std output
./test.sh: line 7: whatthis: command not found
std output
./test.sh: line 7: whatthis: command not found
std output
./test.sh: line 7: whatthis: command not found
std output
./test.sh: line 7: whatthis: command not found
std output
./test.sh: line 7: whatthis: command not found
std output
./test.sh: line 7: whatthis: command not found
std output

我们通过ps aux| grep test.sh可以找到这个脚本的进程ID:

1
2
root@ezreal:~# ps aux | grep test.sh | grep -v 'grep '
root 31807 0.0 0.1 12228 3296 pts/0 S+ 09:44 0:00 /bin/bash ./test.sh

进程ID为31807,然后打开ls -al /proc/31807/fd可以看到这三个文件描述符。

1
2
3
4
5
6
7
8
root@ezreal:~# ls -al /proc/31807/fd
total 0
dr-x------ 2 root root 0 Aug 24 09:44 .
dr-xr-xr-x 9 root root 0 Aug 24 09:44 ..
lrwx------ 1 root root 64 Aug 24 09:44 0 -> /dev/pts/0
lrwx------ 1 root root 64 Aug 24 09:44 1 -> /dev/pts/0
lrwx------ 1 root root 64 Aug 24 09:46 2 -> /dev/pts/0
lr-x------ 1 root root 64 Aug 24 09:46 255 -> /root/test.sh

如果这个时候我们想将这个shell脚本输出都重定向到一个log文件中。我们可以这样处理:

./test.sh >> test.log

运行之后我们发现,标准输出是可以追加到日志中去,但是错误输出无法追加,

1
2
3
4
5
root@ezreal:~# ./test.sh >> test.log 
./test.sh: line 7: whatthis: command not found
./test.sh: line 7: whatthis: command not found
./test.sh: line 7: whatthis: command not found

这个时候就需要使用2>&1这个命令了。这个命令的含义就是将错误输出重定向到标准输出中去,而标准输出我们重定向到了test.log中,就意味着错误输出也重定向到了test.log中了。但是为什么要加上&这个符号呢。因为重定向符号>右侧必须是一个文件,&1就代表引用了标准输出这个文件描述符。

这时我们更改命令如下:

1
root@ezreal:~# ./test.sh >> test.log  2>&1

发现没有错误输出了。

然后查看该命令的进程相关信息:

1
2
3
4
5
6
7
8
9
10
11
root@ezreal:~# ps aux | grep test.sh | grep -v 'grep '
root 1362 0.0 0.1 12228 3136 pts/0 S+ 09:55 0:00 /bin/bash ./test.sh
root@ezreal:~# ls -al /proc/1362/fd
total 0
dr-x------ 2 root root 0 Aug 24 09:55 .
dr-xr-xr-x 9 root root 0 Aug 24 09:55 ..
lrwx------ 1 root root 64 Aug 24 09:55 0 -> /dev/pts/0
l-wx------ 1 root root 64 Aug 24 09:55 1 -> /root/test.log
l-wx------ 1 root root 64 Aug 24 09:56 2 -> /root/test.log
lr-x------ 1 root root 64 Aug 24 09:56 255 -> /root/test.sh
root@ezreal:~#

可以发现文件描述符1,也就是stdout,文件描述符2,也就是stderr都指向了test.log这个文件了。我们查看一下test.log文件可以发现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
./test.sh: line 7: whatthis: command not found
std output
./test.sh: line 7: whatthis: command not found
std output
./test.sh: line 7: whatthis: command not found
std output
./test.sh: line 7: whatthis: command not found
std output
./test.sh: line 7: whatthis: command not found
std output
./test.sh: line 7: whatthis: command not found
std output
./test.sh: line 7: whatthis: command not found
std output
./test.sh: line 7: whatthis: command not found
std output
./test.sh: line 7: whatthis: command not found
std output
./test.sh: line 7: whatthis: command not found
std output

发现错误也打印进来了。


shell中的 2>&1含义
https://randzz.cn/a2119cb22468/shell中的-2-1含义/
作者
Ezreal Rao
发布于
2021年8月24日
许可协议