进一步阅读

进一步阅读

当您想将 stdout 和 stderr 重定向到同一个文件时,可以使用command 1>file.txt 2>&1, 或command &>file.txt。但是为什么 的行为command 1>file.txt 2>file.txt与上面两个命令不同呢?

以下是验证命令。

$ cat redirect.sh
#!/bin/bash

{ echo -e "output\noutput" && echo -e "error" 1>&2; } 1>file.txt 2>&1
{ echo -e "output\noutput" && echo -e "error" 1>&2; } 1>file1.txt 2>file1.txt
{ echo -e "error" 1>&2 && echo -e "output\noutput"; } 1>file2.txt 2>file2.txt
{ echo -e "output" && echo -e "error\nerror" 1>&2; } 1>file3.txt 2>file3.txt
{ echo -e "error\nerror" 1>&2 && echo -e "output"; } 1>file4.txt 2>file4.txt

$ ./redirect.sh

$ echo "---file.txt---"; cat file.txt;\
echo "---file1.txt---"; cat file1.txt; \
echo "---file2.txt---"; cat file2.txt; \
echo "---file3.txt---"; cat file3.txt; \
echo "---file4.txt----"; cat file4.txt;
 ---file.txt---
output
output
error
---file1.txt---
error

output
---file2.txt---
output
output
---file3.txt---
error
error
---file4.txt----
output
rror

从结果来看,运行时第二个回显字符串似乎覆盖了第一个回显字符串command 1>file.txt 2>file.txt,但我不知道为什么会这样。 (有什么地方可以参考吗?)

答案1

你需要知道两件事:

  • 一个开放的文件描述符进程的应用程序模式端已知引用一个内部内核对象,称为文件描述,这是一个打开文件的实例。每个文件可以有多个文件描述,并且多个文件描述符共享一个文件描述。
  • 当前文件位置是 a 的一个属性文件描述。因此,如果多个文件描述符映射到单个文件描述,则它们都共享相同的当前文件位置,并且使用一个此类文件描述符对文件位置进行的更改会影响所有其他此类文件描述符。

    此类更改是通过调用read()/ readv()write()/ writev()lseek()等系统调用的进程来实施的。该echo命令当然调用write()/ 。writev()

那么发生的事情是这样的:

  • command 1>file.txt 2>&1只创建一个文件描述,因为 shell 只打开一个文件一次。外壳使两个都标准输出和标准错误文件描述符映射到该单个文件描述。它重复项标准输出到标准错误。因此,通过任一文件描述符进行写入都会移动共享的当前文件位置:每次写入都会在前一次写入公共文件描述之后进行。正如您所看到的,命令的结果echo不会相互覆盖。
  • command 1>file.txt 2>file.txt创造文件描述,因为 shell 打开同一个文件两次,以响应两次显式重定向。标准输出和标准错误文件描述符映射到两个不同的文件描述,然后这两个文件描述又映射到同一个文件。两个文件描述具有完全独立的当前文件位置,并且每次写入都会立即执行同一文件描述上的前一个写入。正如您所看到的,结果是通过一个写入的内容可以根据您执行写入的顺序以各种不同的方式覆盖通过另一个写入的内容。

进一步阅读

答案2

使用>告诉它覆盖该文件。由于您在两个不同的操作中将 stdout 和 stderr 写入文件,因此最后一个写入将覆盖第一个。

你可以做:

command 1>>file.txt 2>>file.txt

或者

command &>file.txt仅 bash v4 及以上版本。

>>告诉它附加文件,这样它就不会替换以前操作的输出。

&>只是一种更简单的书写方式2>&1

相关内容