ls 如何知道如何输出其结果?

ls 如何知道如何输出其结果?

在创建 bash 脚本时,我发现此代码ls将所有文件放在一行上:

pi@raspberrypi:~/ptlrestinterface$ ls
update.sh   web.config   MyApp.runtimeconfig.json   

仍然ls | head -n1只打印第一个文件:

pi@raspberrypi:~/ptlrestinterface$ ls | head -n1
update.sh

我希望它输出整行,而不是第一个文件。

当通过管道传输输出时hexdump,我看到ls总是在每个条目后输出一个0a,但是在控制台上,它将它们放在彼此旁边。

显然ls对控制台(或控制台ls)有一些了解。它是如何工作的?我在哪里可以找到有关此行为的文档?

答案1

它调用文件描述符isatty()上的 libc 函数stdout来确定输出是否到达终端。

在内部,尝试使用特定于 tty 设备的调用isatty()之一- 最有可能(检索命令显示的通用 tty 设置);如果成功,则该文件就是一个 tty 设备。ioctl()ioctl(TCGETS)stty

$ python
>>> sys.stdout.isatty()
True

这会影响 ls 是否默认将其输出列化,是否默认使用颜色,以及一些其他事项,例如是否将文件名加引号。

如果stdout确实是终端,则ls使用另一个 tty 特定的方法ioctl(TIOCGWINSZ)来检索其尺寸(在现代系统中,这些尺寸已由终端仿真器存储在那里)以找出它可以容纳多少列。该stty size命令也会获取这些;尝试在 下运行它strace

全屏程序还会对SIGWINCH内核每次终端仿真器更新 tty 尺寸时发送的信号做出反应,表明它们需要以新的尺寸重新绘制所有内容。

答案2

为了获得不太技术性的解释,请观察尝试这两个命令时发生的情况:

$ ls
update.sh   web.config   MyApp.runtimeconfig.json

$ ls | cat
update.sh
web.config
MyApp.runtimeconfig.json

通过管道传输cat“不做任何事情”,只是ls“注意到”它的输出正在被管道传输到某处。因此它会相应地改变其行为。

一旦你理解了ls输出的内容,你就可以直接知道当它经过时会发生什么head -n1

相关内容