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

前言

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

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

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

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

1.标准输出

 在终端输入

echo hello
hello

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

每个基于 Unix操作系统都有一个输出的默认位置”的概念。由于这个短语比较啰嗦,所以大家都称它为“标准输出”或“stdout”,读作standard outshell(可能是 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将其作为标准输入传递给sedsed对其进行操作后,再输出到标准输出。

 那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

 这行命令做了两件事

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

$ 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

cmdstdout将会被重定向到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

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

原文地址:https://blog.csdn.net/dddgggd/article/details/129052944

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如若转载,请注明出处:http://www.7code.cn/show_10647.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注