像这样的命令如何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