尝试计算当前目录中的文件数,我发现ls -1 | wc -l
,这意味着:将文件列表(其中每个文件名打印在新行中)发送到 wc 的输入,其中-l
将计算输入的行数。这是有道理的。
我决定简单地尝试一下ls | wc -l
,并且非常惊讶它还给了我正确数量的文件。我想知道为什么会发生这种情况,因为ls
没有选项的命令会在一行上打印文件名。
答案1
从info ls
:
'-1'
'--format=单列'每行列出一个文件。 当标准输出不是终端时,这是“ls”的默认值。
当您通过管道输出 的输出时ls
,每一行都会得到一个文件名。
ls
仅当输出供人眼使用时,才按列输出文件。
这是ls
决定要做什么的地方:
switch (ls_mode)
{
case LS_MULTI_COL:
/* This is for the 'dir' program. */
format = many_per_line;
set_quoting_style (NULL, escape_quoting_style);
break;
case LS_LONG_FORMAT:
/* This is for the 'vdir' program. */
format = long_format;
set_quoting_style (NULL, escape_quoting_style);
break;
case LS_LS:
/* This is for the 'ls' program. */
if (isatty (STDOUT_FILENO))
{
format = many_per_line;
/* See description of qmark_funny_chars, above. */
qmark_funny_chars = true;
}
else
{
format = one_per_line;
qmark_funny_chars = false;
}
break;
default:
abort ();
}
来源:http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/ls.c
答案2
由于 的输出ls
取决于 std 输出,因此终端和管道的输出有所不同。尝试
/bin/ls | cat
答案3
从历史上看,ls
每行将其输出写入一个文件,这是一种方便使用其他基于文本的 Unix 工具(例如wc
)进行处理的格式。然而,在没有回滚功能的 24 行终端上,大型列表往往会滚动到屏幕之外,从而很难找到您要查找的内容。因此,在某些时候,BSD 开发人员改变了行为因此,当打印到终端时,ls
会将其输出格式化为多列。写入管道或文件时保留了旧的行为,以避免破坏现有的 shell 脚本 --- 并且因为在使用诸如 之类的命令处理输出时,旧的行为更有用wc
。将多列输出合并到终端ls
并使其成为终端上的默认输出的决定,锻炼了罗布·派克不少; Research Unix 直到第 8 版(直接基于 BSD)才采用新功能,而 Plan 9 恢复为单独的命令,ls
用于脚本和lc
交互式使用,通过lc
shell 脚本调用和提供多列输出的ls
命令。mc
-1
和选项-C
是ls
恢复理智的迟来的尝试,至少允许用户强制使用特定的输出格式,而不管输出目的地如何。
答案4
为什么“ls | wc -l”显示当前目录中正确的文件数量?
嗯,这是一个错误的前提。它不是!尝试这个:
mkdir testdir
cd testdir
# below two lines are one command, the newline is quoted so will be part of argument
echo text | tee "file
name"
ls -l
ls | wc -l
最后一行的输出是 2。
请注意,在命令中打印到控制台时ls -l
,LS不会按原样打印换行符,而是打印?
.但这是一个专门实现的功能LS,当它检测到输出将发送到实际终端时,它会执行此操作,以避免有趣的文件名弄乱终端。这一相同的检测确定文件名是每行打印一个(在管道中)还是根据终端宽度打印(这显然只有在存在时才有意义)是具有宽度的终端)。你可以愚弄LS使用命令,例如ls | cat
如果您想要打印原始文件名,并用换行符分隔。
wc -l
只是计算行数,如果文件名恰好包含换行符,那么厕所会将其视为两行。
LS还有开关强制隐藏控制字符-q
/ --hide-control-chars
,因此ls -q | wc -l
实际上应该给出 by 列出的文件的准确数量ls
(通常与目录中的实际文件数量不同,没有-a
开关),因为这样只有换行符LS输出应该是那些分隔文件名的文件。