了解输出到 stdout 和常规文件的区别

Understanding the difference over output to stdout and a regular file

这是 ls 命令的输出:

$ ls
addr.sh  hello.txt  test.sh  xxx.txt

这里我们有相同的命令重定向到 stderr:

$ ls 1>&2
addr.sh  hello.txt  test.sh  xxx.txt

产生几乎相同的输出。

然而,重定向到常规文件会导致 ls 产生多行输出:

$ ls > xxx.txt
$ cat xxx.txt
addr.sh
hello.txt
test.sh
xxx.txt

为什么以及幕后发生了什么?

Why

因为有人这样编程。

what is happening

您的 ls 实现检查标准输出是否连接到终端设备。如果是,它会输出一个漂亮的打印输出,以类似列的方式用空格分隔。如果输出不是终端设备,它会输出一个换行符分隔的列表。*

检查文件描述符是否在终端上打开可以使用内部调用 isatty() C 函数的 test -t FD 命令完成。

ls 基本上是这样的:

{ if [ -t 1 ]; then ls -C; else ls -1; fi }
# From man ls:
# -C     list entries by columns
# -1     list one file per line.

当输出不是终端设备时,许多实用程序会改变它们的行为。

*请注意,当输出不是终端 The default format shall be to list one entry per line to standard output; the exceptions are to terminals [...].

时,POSIX ls specification 强制输出为每个文件一个条目的列表

behind the scenes?

我假设您有 coreutils ls 实现。在 coreutils/ls.c#L1886 程序只检查是否 isatty(STDOUT_FILENO) 并根据它设置引用样式和类似列或类似换行符的输出。