ls 命令的操作因收件人而异

ls 命令的操作因收件人而异

像这样的命令如何ls知道它的标准输出是什么?

ls根据目标标准输出的不同,操作似乎有所不同。例如,如果我这样做:

ls /home/matt/tmp 

结果是:

a.txt b.txt c.txt

但是如果我这样做

ls /home/matt/tmp | cat

结果是(即每个结果换行):

a.txt
b.txt
c.txt

该进程传递了一个用于 stdout 的文件描述符 1,对吧?它如何确定如何格式化结果?文件描述符是否泄露信息?

答案1

ls程序用于isatty()了解 fd 1 是 tty 还是其他东西(管道、文件等……)。从man 3 isatty

int isatty(int fd);

描述
isatty()函数测试fd打开的文件描述符是否引用终端


更新:coreutils中的第 1538 行ls.c(git 修订版 43a987e1):

  if (isatty (STDOUT_FILENO))
    {
      format = many_per_line;
      /* See description of qmark_funny_chars, above.  */
      qmark_funny_chars = true;
    }

many_per_line应该是自我描述的。)

答案2

不是一个确切的答案,而是一个例子。在 Bash 脚本中,您可以使用test/实现类似的[[效果-t

-t FD True if FD is opened on a terminal.

像这样使用它:

bash-4.2$ where() { [[ -t 1 ]] && echo 'my output goes to TTY' || echo 'my output is redirected'; }

bash-4.2$ where
my output goes to TTY

bash-4.2$ where | cat
my output is redirected

bash-4.2$ where > test.file
bash-4.2$ cat test.file
my output is redirected

答案3

来自 OpenBSDls(1) 手动的:

默认情况下,ls 每行列出一个条目到标准输出;终端或指定 -C、-m 或 -x 选项时除外。

然后,后来:

-1(数字“一”。)强制输出为每行一个条目。当输出不输出到终端时,这是默认设置。

[...]

-C 强制多列输出;这是输出到终端时的默认设置。

答案4

您可以ls使用该命令在伪终端中执行script ,将 的输出通过管道传输ls到另一个命令,并获得相同的输出格式,就好像没有这样的 stdout 流管道一样,即,就像 stdout 是终端 (tty) 一样。

isatty()对于Stéphane Gimenez 已经指出的基本机制,请参见ls.c

ls -G /
ls -G / | cat
script -q /dev/null ls -G / | sed $'s/\r$//g' | cat

# tty | cat
# script -q /dev/null tty | cat

相关内容