重定向标准输出
> 重定向当前命令的标准输出(STDOUT)到一个文件或者一个描述符。
下面的例子把ls命令的输出存到file.txt文件
- ls >file.txt
- > file.txt ls
目标文件如果不存在就会被创建,或者文件被截断。
如果不指定,默认重定向描述符是标准输出或1。下面的命令等同于上面的例子:
- ls 1>file.txt
追加 vs 截断
截断 >
1.如果文件不存在则创建
2.截断(删除文件内容)
3.写入文件
- $ echo "first line" > /tmp/lines
- $ echo "second line" > /tmp/lines
- $ cat /tmp/lines
- second line
追加 >>
1.如果文件不存在则创建
2.追加文件(在文件底部写)
- # Overwrite existing file
- $ echo "first line" > /tmp/lines
- # Append a second line
- $ echo "second line" >> /tmp/lines
- $ cat /tmp/lines
- first line
- second line
重定向标准输出和标准错误
文件描述符像0和1都是指针。我们更改的是文件描述符的指向。
>/dev/null意思是1指向/dev/null。
首先我们把1(STDOUT)指向/dev/null,然后2指向1(不管1指向什么)。
- echo_to_stdout_and_stderr >/dev/null 2>&1
可以更短点:
echo_to_stdout_and_stderr &> /dev/null
使用命名管道
有时候你想把一个程序的标准输出作为其它多个程序的标准输入,这时候就不能用标准管道了,不过你可以写入一个临时文件,如:
- touch tempFile.txt
- ls -l > tempFile.txt &
- grep ".log" < tempFile.txt
这个方法可以在大多数情况下有效,但谁都不知道tempFile.txt会被哪个程序删除或者修改里面的内容。这时候命名管道就可以用上场了。
- mkfifo myPipe
- ls -l > myPipe
- grep ".log" < myPipe
myPipe在技术上是一个文件,所以我们来用ls -l看下当前创建管道的目录
- mkdir pipeFolder
- cd pipeFolder
- mkfifo myPipe
- ls -l
输出为:
prw-r–r– 1 root root 0 Jul 25 11:20 myPipe
注意权限的第一个字符,显示是pipe,不是文件。
现在我们做了有意思的。
打开一个终端,在一个空目录创建管道:
- mkfifo myPipe
现在我们输入点东西到管道:
- echo "Hello from the other side" > myPipe
你会注意到这个命令被挂起了,让我们打开一个新的终端,输入:
- cat < myPipe
你会发现当”hello from the other side”输出后,终端1就完成了,终端2也一样。
现在我们反向运行程序,先执行cat < myPipe,然后再输入点东西到myPipe,它仍然按预期工作,因为一个程序会一起等待直到管道中被输入一些东西。
命名管道在终端间或程序间传递信息时会非常有用。
输出错误信息到标准错误
错误信息通常为了调度会包含在脚本里。简单的输出错误信息如下:
- cmd || echo ‘cmd failed’
可能会在简单的场景工作,但不是通常的做法。在这个例子中,错误信息会会污染脚本实际的输出。简单来说,错误信息应该输出到标准错误而不是标准输出,如:
- cmd || echo ‘cmd failed’ >/dev/stderr
其它例子:
- if cmd; then
- echo ‘success’
- else
- echo ‘cmd failed’ >/dev/stderr
- fi
可以封装成一个函数:
- err(){
- echo "E: $*" >>/dev/stderr
- }
- err "My error message"