Linux中的输入,输出和错误重定向

时间:2020-03-05 15:31:11  来源:igfitidea点击:

如果我们熟悉基本的Linux命令,我们还应该了解输入输出重定向的概念。

Stdin,stdout和stderr

运行Linux命令时,有三个数据流播放其中部分:

  • 标准输入(STDIN)是输入数据的源。

默认情况下,stdin是从键盘输入的任何文本。它的流ID是0。

  • 标准输出(stdout)是命令的结果。

默认情况下,它显示在屏幕上。它的流ID是1.

  • 标准错误(stderr)是命令生成的错误消息(如果有的话)。

默认情况下,STDEDR也会显示在屏幕上。它的流ID是2.

这些流包含纯文本中的数据在被叫缓冲存储器中。

把它想象成水流。
你需要一个水的来源,例如水龙头。
我们将管道连接到它,我们可以将其存放在桶(文件)或者水中植物(打印它)。
如果需要,我们还可以将其连接到另一个水龙头。
基本上,你正在重定向水。

Linux还具有这种重定向的概念,在那里我们可以将STDIN,STDOUT和STDEDR从其平常的目的地重定向到另一个文件或者命令(甚至是打印机等外围设备)。

让我展示重定向是如何运作的以及如何使用它。

输出重定向

第一种和最简单的重定向形式是输出重定向也称为STDOUT重定向。

我们已经知道,默认情况下,屏幕上会显示命令的输出。
例如,我使用ls命令列出所有文件,这是我得到的输出:

Hyman@theitroad:~$ls
appstxt  new.txt  static-ip.txt

使用输出重定向,可以将输出重定向到文件。
如果此输出文件不存在,则shell将创建它。

command > file

例如,让我将ls命令的输出保存到名为contance.txt的文件:

Hyman@theitroad:~$ls > output.txt

事先创建输出文件

我们认为此输出文件的内容应该是什么?
让我用CAT命令向我们展示一个惊喜:

Hyman@theitroad:~$cat output.txt 
appstxt
new.txt
output.txt
static-ip.txt

你注意到那里包含output.txt吗?
我故意选择这个例子来告诉你这个。

在运行预期命令之前创建重定向的输出文件。
为什么?
因为它需要使输出目的地准备好输出输出。

添加而不是Clobber

一个经常忽略的问题是,如果我们重定向到已经存在的文件,则shell将首先删除(clobber)文件。

这意味着将删除输出文件的现有内容并由命令的输出替换。

我们可以使用>>重定向语法追加,而不是覆盖它。

command >> file

提示:我们可以使用以下方法禁止在当前shell会话中进行Clobbering:set -c

为什么你会重定向stdout?
我们可以将输出存储以供将来参考并稍后分析。
当命令输出太大时,它会特别有用,它需要所有的屏幕。
这就像收集日志。

管道重定向

在看到STDIN重定向之前,我们应该了解管道重定向。
这更为常见,可能你会使用它很多。

通过管道重定向,我们将命令的标准输出发送到另一个命令的标准输入。

command 1 | command 2

让我向你展示一个实际的例子。
说,我们希望计算当前目录中的可见文件的数量。
我们可以使用LS -1(它是数字,而不是字母L)来显示当前目录中的文件:

Hyman@theitroad:~$ls -1
appstxt
new.txt
output.txt
static-ip.txt

我们可能已经知道WC命令用于计数文件中的行数。

如果将这两个命令与管道组合,那就是你得到的:

Hyman@theitroad:~$ls -1 | wc -l
4

使用管道,两个命令共享相同的内存缓冲区。
第一个命令的输出存储在缓冲区中,然后将相同的缓冲区用作下一个命令的输入。

我们将看到管道中最后一个命令的结果。
这很明显,因为早期命令的STDOUT被馈送到下一个命令而不是进入屏幕。

管道重定向或者管道不仅限于连接两个命令。
只要一个命令的输出可以用作下一个命令的输入,我们可以连接更多命令。

command_1 | command_2 | command_3 | command_4

记住stdout/stdin是一个块的数据,而不是文件名

一些新的Linux用户在使用重定向时会变得混淆。
如果命令返回一堆文件名作为输出,则无法使用这些文件名作为参数。

例如,如果我们使用Find命令查找以.txt结尾的所有文件,则无法通过管道将找到的文件移动到新目录,而不是直接如下:

find . -type f -name "*.txt" | mv destination_directory

这就是为什么你经常看到与exec或者xargs命令共轭使用的查找命令。

这些特殊命令将具有束文件名的文本转换为filename',可以作为参数传递。

find . -type f -name "*.txt" | xargs -t -I{} mv {} ../new_dir

输入重定向

我们可以使用STDIN重定向将文本文件的内容传递给这样的命令:

command < file

你不会看到stdin被使用了很多。
这是因为大多数Linux命令接受文件名作为参数,因此通常不需要stdin重定向。

参见这一点:

head < filename.txt

上面的命令可能只是头文件名.txt(没有<)。

这不是Stdin重定向完全没用。
有些命令依赖它。
拍摄例如TR命令。

此命令可以执行很多但在下面的示例中,它将输入文本从较低到大写转换为:

tr a-z A-Z < filename.txt

事实上,使用STDIN是专门用于避免CAT命令的不必要的使用。

例如,许多人将使用上面的例子与CAT,然后使用TR。
坦率地说,这里不需要使用cat 。

cat filename.txt | tr a-z A-Z

结合重定向

我们可以根据需要组合STDIN,STDOUT和管道重定向。

例如,下面的命令列出了当前目录中的所有.txt文件,然后对这些.txt文件进行计数并将输出保存到新文件。

ls *.txt | wc -l > count.txt

错误重定向

有时,当我们运行一些命令或者脚本时,我们会看到它在屏幕上显示错误消息。

Hyman@theitroad:~$ls -l ffffff > output.txt
ls: cannot access 'ffffff': No such file or directory

在本文的开头,我提到有三个数据流且STDERR是默认情况下在屏幕上显示的输出数据流之一。

我们也可以将STDERR重定向。
由于它是一个输出数据流,我们可以使用我们用于STDOUT重定向的相同>或者>>重定向符号。

但是,当它们都是输出数据流时,我们如何区分STDOUT和STDERR?
通过他们的流ID(也称为文件描述符)。

|数据流|.流ID |
| --- - | --- |
| stdin | 0 |
| stdout | 1 |
| stderr | 2 |
| -T,| -list|
| -u,| -Update |
| -x,| -extract, -get |
| -J,| -bzip2 |
| -z,| -gzip,-gunzip,-ungzip |

默认情况下,使用输出重定向符号>时,它实际上意味着1>。
用文字说,我们正在此处在此处输出具有ID 1的数据流。

当我们必须重定向STDERR时,我们可以使用其ID,如2>或者2 >>。
这表示输出重定向是用于数据流STDERR(ID 2)。

STDERR重定向示例

让我用一些例子向我们展示。
假设我们只想保存错误,我们可以使用这样的内容:

Hyman@theitroad:~$ls fffff 2> error.txt
Hyman@theitroad:~$cat error.txt 
ls: cannot access 'fffff': No such file or directory

那很简单。
让我们稍微复杂(有用):

Hyman@theitroad:~$ls -l new.txt ffff > output.txt 2> error.txt 
Hyman@theitroad:~$cat output.txt 
-rw-rw-r-- 1 igi igi 0 Jan  5 10:25 new.txt
Hyman@theitroad:~$cat error.txt 
ls: cannot access 'ffff': No such file or directory

在上面的示例中,LS命令尝试显示两个文件。
对于一个文件,它获得了成功,另一个文件,它会出错。
所以我在这里所做的是将stdout重定向到out.txt(with>)和stderr到错误.txt(有2个>)。

我们还可以将stdout和stderr重定向到同一文件。
有办法做到这一点。

在下面的示例中,我首先将stderr(用2 >>)发送到Comply.txt文件中。
然后,STDOUT(用>>)以添加模式发送到同一文件。

Hyman@theitroad:~$ls -l new.txt fff 2>> combined.txt >> combined.txt 
Hyman@theitroad:~$cat combined.txt 
ls: cannot access 'fff': No such file or directory
-rw-rw-r-- 1 igi igi 0 Jan  5 10:25 new.txt

另一种方式,这是首选的方式,是使用类似于2>&1的东西。
这可以大致翻译成"将stderr重定向到与stdout相同的地址"。

让我们参加上一个例子,这次使用2>&1将两个stdout和stderr重定向到同一文件。

Hyman@theitroad:~$ls -l new.txt fff > output.txt 2>&1
Hyman@theitroad:~$cat output.txt 
ls: cannot access 'fff': No such file or directory
-rw-rw-r-- 1 igi igi 0 Jan  5 10:25 new.txt

请记住,我们不能使用2 >>&1在添加模式下使用它。
2>&1已经进入了添加模式。

我们也可以使用2>首先使用1>&2将stdout重定向到与stderr相同的文件。
基本上,它是">&",它将一个输出数据流重定向到另一个。

概括

  • 有三个数据流。一个输入,stdin(0)和两个输出数据流stdout(1)和stderr(2)。
  • 键盘是默认的STDIN设备,屏幕是默认输出设备。
  • 输出重定向用于>或者>>(用于添加模式)。
  • 输入重定向用于<。
  • 使用2 >>>可以重定向STDERR。
  • 可以使用2> 1组合STDEDR和STDOUT。

由于我们正在学习重定向,我们还应该了解TEE命令。

此命令使我们可以显示标准输出并同时保存到文件。