shell中的输出重定向语法

gwo2fgha  于 2023-02-09  发布在  Shell
关注(0)|答案(2)|浏览(179)

我一直在做实验看看两者之间有什么区别

command >file 2> file

以及

command >file 2>&1

我还没能做到。我知道第二个命令说要把错误发送到文件描述符1(stdout)已经到达的地方,第一个命令会为它创建一个新的空文件,但是这怎么能被看到呢?
另外,我在哪里可以找到更多关于文件描述符/io语法及其工作原理的信息?

ldxq2e6h

ldxq2e6h1#

不同之处在于>file 2>&1只打开文件一次,但随后允许访问该文件的单个连接(从技术上讲,"open file description" in the kernel)通过文件描述符#1(标准输出)和#2(stderr)。由于对stdout和stderr的写入是通过同一连接进行的(“打开文件描述”),它们以一致、协调的方式写入文件(类似的协调适用于打开的文件,用于输入多个描述符)。
另一方面,>file 2>file打开文件 * 两次 *(在内核中创建两个单独的打开文件描述符),因此通过两个文件描述符写入文件是不协调的,它们基本上会互相影响。
举一个例子可以帮助你理解我的意思。下面是一个简短的subshell命令,它将一些内容打印到stdout,然后将一部分内容打印到stderr,再将更多内容打印到stdout。首先在>file 2>&1上尝试一下,它会达到你所期望的效果:

$ (echo abc; echo 123456 >&2; echo def) >file 2>&1
$ cat file
abc
123456
def

这并不奇怪,对吧?现在让我们尝试使用到该文件的单独连接:

$ (echo abc; echo 123456 >&2; echo def) >file 2>file
$ cat file
1234def

这可能不是您所期望的,这里发生的情况是,第一个echo命令向stdout发送“abc”,后跟一个换行符,然后它被写入文件的前四个字节,第二个echo命令向stderr发送“123456”,后跟一个换行符;由于stderr连接是独立的,它仍然指向文件的开头,所以它被写入文件的前7个字节(覆盖已经存在的“abc“),然后第三个echo发送“def”和一个换行符到stdout;由于stdout连接指向文件的字节#5(在最后一次写入该连接结束的位置过去一个字节),因此从那里开始写入,这将覆盖第二个echo在那里写入的内容的“56“部分。
所以多次打开同一个文件会导致混乱的结果,这就是为什么你应该总是使用>file 2>&1而不是>file 2>file

ujv3wf0j

ujv3wf0j2#

这是一种不同的观察方式

$ some-command > file > file
something to stderr if some-commands outputs
$ set -o noclobber
$ some-command > file > file
bash: file: cannot overwrite existing file
$ rm file
$ some-command > f1 2>&1
# no error

相关问题