一文搞懂Linux的标准输出/错误重定向

13 篇文章 1 订阅
3 篇文章 1 订阅
文章介绍了Linux系统中一切皆文件的概念,详细讲解了标准输入、标准输出和标准错误的区别,并通过示例阐述了如何使用输出重定向将shell命令的输出保存到文件,以及如何使用文件描述符和管道进行更复杂的重定向操作。此外,还提到了如何将标准错误重定向到标准输出以及输出静音的技巧。
摘要由CSDN通过智能技术生成

前言

 今天在写一个脚本时,需要将shell命令和可执行程序的输出重定向在某一个log文件中,但是遇到了点小问题,索性就研究下输出重定向到底怎么回事。

 Linux系统,有一个非常重要概念,就是一切皆文件。在使用shell脚本时,系统为了能够进行接收外部输入,同时向外部输出,将三个文件始终保持在打开的状态,并使用三个文件描述符0,1,2来分别指向这三个文件,以此来完成标准输入,标准输出,标准错误输出。

  • 标准输入:由键盘输入

  • 标准输出:输出到屏幕

  • 标准错误:输出到屏幕

 在正常情况下,我们执行shell命令时,其输出总是标准输出或者标准错误,因此总是会将输出的信息,不论是正常信息还是报错信息,都会打印在屏幕上,但有时我们不希望这些输出打印在屏幕上,而是希望这了信息能被保存到指定的文件中,这就是输出重定向。

 那么,究竟什么是标准输入/标准输出/标准错误呢?下面为大家一一介绍。

1.标准输出

 在终端输入

echo hello
hello

 终端会打印hello,但是我们echo出来的hello,到底去了什么地方?

 每个基于 Unix 的操作系统都有一个“输出的默认位置”的概念。由于这个短语比较啰嗦,所以大家都称它为“标准输出”或“stdout”,读作standard out。 shell(可能是 bash 或 zsh)一直在监视默认输出位置。当 shell 在标准输出那里看到新的输出时,它会将其打印在屏幕上,以便我们可以看到它。否则,shell不去监视标准输出位置,echo hello会将“hello”发送到那个默认位置,但我们却看不到。

2.标准输入

 标准输入(stdin)是命令监听信息的默认位置,尝试在终端输入cat,不添加任何参数

cat 
hello
hello
1234
1234

 不论输入什么,shell会将你的输入再次打印,shell怎么读取到你的输入呢,和标准输出类似,shell会一直监视默认输入位置,一有新的输入进来,shell便会把数据读进来,然后输出到stdout

3.标准错误

 标准错误(stderr)和stdin/stdout很像,区别就是stderr是错误信息存储的地方,例如, cat一个不存在的文件

cat ttt
cat: ttt: No such file or directory

 似乎和stdout没什么两样,但是我们借助管道来验证一下,在linux中,管道是将一个命令的stdout连接到另一个命令的stdin,可以使用管道符号|来完成这个操作,例如

echo "hello there"
hello there
echo "hello there" | sed "s/hello/hi/"
hi there

 这里的sed是将hello替换为hi,上面命令中,echo将hello there传输到标准输出,然后通过管道将hello there将其作为标准输入传递给sed,sed对其进行操作后,再输出到标准输出。

 那cat打印出的信息,到底是stdout呢还是stderr呢?看这个命令

cat ttt | sed "s/No such/hello world/"
cat: ttt: No such file or directory

  如果 cat ttt打印出来的信息是stdout的话,那No such会被替换成hello world,但似乎并没有被替换到,是的,cat ttt打印出的信息,是stderr而不是stdout。管道只会接收stdout,而不会接收stderr

4. 重定向

 这里我们终于可以知道什么是重定向了,默认情况下,我们shell执行的命令的输出一定会到stdout或者stderr,如果我们不想让信息输出到stdout或者stderr,那就要用到重定向了,我们可以使用>将输出进行重定向。

$ echo "hello world" > file
$ cat file
hello world

 这行命令做了两件事

  • file不存在,则创建
  • file存在,则用hello world覆盖其内容

 如果只是想追加内容而不是覆盖原有内容,则可以使用>>

$ echo "hello world" > file
$ cat file
hello world
$ echo "go go go" >>file
$ cat file
hello world
go go go

 其中,如果>或者>>前不添加文件描述符,则默认是将标准输出重定向到file,如果想重定向stderr,则需要表示为1 > file或者2 > file

5.文件描述符

 文件描述符(File descriptor)是表示输入/输出源的正整数,例如stdin是0,stdout是1,stderr是2,这些数字是由POSIX标准定义的,MacOS和Linux都实现了这个标准的一部分。

如果想将输出重定向到某一文件描述符,则需要借助>&运算符并跟上文件描述符来完成

# Redirect stdout to stdout (FD 1)
echo "hello there" >&1
hello there
# Redirect stdout to stderr (FD 2)
echo "hello there" >&2
hello there

 这和上面的输出重定向到某一文件基本一样,只不过重定向的最终目标变成了stdoutstderr,让我们继续通过管道看看这两个输出有什么区别

echo "no changes" >&1 | sed "s/no/some/"
some changes
# Redirect to stderr, so it does not come through
echo "no changes" >&2 | sed "s/no/some/"
no changes

 原理还是和上面一样,第一行将输出重定向到了标准输出,所以管道会将其传递给sed,第二行经echo的输出重定向到了标准错误,管道无法传递。

6.将stderr重定向到stdout

 如果一个脚本,将输入的参数的三个参数分别重定向到了stdout stderr stdout,那么一个命令就出现了两种不同的输出,使用管道时,就无法传递全部的输出作为下个命令的输入,我们编写一个这样的command

#!/bin/bash

for f in $@; do
  if [[ $f == "file2" ]]; then
    echo "stderr file2" >& 2
  else
    echo "stdout $f"
  fi
done
$ bash command file1 file2 file3
stdout file1
stderr file2
stdout file3

 用管道来处理,则只会处理部分,file2是stderr,无法被管道抓取。

$ bash command file1 file2 file3 | sed "s/^/Robot says: /"
stderr file2
Robot says: stdout file1
Robot says: stdout file3

 我们可以通过2>&1将标准错误重定向给标准输出,例如

cat ttt 2>&1 | sed "s/No such/hello world/"
cat: ttt: hello world file or directory

 由于stderr重定向到了stdout,管道就将输出的信息传递给了sed,sed做了处理并输出到stdout

同样的,对于command也可以这样做

dexu_tian@VM-4-10-ubuntu:~/Tmp/outputRedirect$ bash ./command file1 file2 file3 2>&1 | sed "s/std/Robot says: std/"
Robot says: stdout file1
Robot says: stderr file2
Robot says: stdout file3

7. 常用用法

 比较常见的用法是将一个命令的stdoutstderr都重定向到某一个文件中,那么它的写法就应该是这样的

cmd > logfile 2>&1

 cmd的stdout将会被重定向到logfile,stderr将会被重定向到stdout,由此实现了stderrstdout被重定向到了logfile.

 像2>&1一样,如果想重定向文件描述符,则需要表示为N >&M,其中N和M是文件描述符,其为1和2时,就是在重定向stdout和stdin了。如果M不是文件描述符,则使用文件名N>filename

8.输出静音

 我们可以通过这种重定向的语法,将所有的输出重定向到/dev/null, 它会吞下所有接收到的内容并且不做任何操作。

echo "hello there" >/dev/null

以上就是本文所要分享的内容,希望大家每天坚持进步~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Michael.Scofield

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值