试图计算当前目录中的文件数,我发现ls -1 | wc -l
,这意味着:将文件列表(其中每个文件名都打印在新行中)发送到 wc 的输入,其中-l
将计算输入的行数。这是有道理的。
我决定简单地尝试一下,ls | wc -l
并且对它也给了我正确数量的文件感到非常惊讶。我想知道为什么会发生这种情况,因为ls
没有选项的命令将文件名打印在一行上。
gle*_*man 57
来自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 ();
}
Run Code Online (Sandbox Code Playgroud)
来源:http : //git.savannah.gnu.org/cgit/coreutils.git/tree/src/ls.c
Jon*_*ast 11
从历史上看,ls
每行写入一个文件,这是使用其他基于文本的 Unix 工具(如wc
)进行处理的一种方便格式。但是,在没有回滚的 24 行终端上,大型列表倾向于滚出屏幕,从而很难找到您要查找的内容。因此,在某些时候,BSD 开发人员改变了行为,以便在打印到终端时ls
将其输出格式化为多列。在写入管道或文件时保留旧行为以避免破坏现有的 shell 脚本 --- 并且因为旧行为在使用类似wc
. 将多列输出合并ls
到终端上并将其设为默认值的决定,相当多地锻炼了 Rob Pike;Research Unix 直到第 8 版(直接基于 BSD)才采用新功能,Plan 9 恢复为单独的命令,ls
用于脚本和lc
交互式使用,具有lc
shell 脚本调用ls
和mc
提供多列输出的命令。
在-1
和-C
选项ls
都恢复神智,至少允许用户强制一个特定的输出格式,无论输出目的地迟来的尝试。
为什么“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
Run Code Online (Sandbox Code Playgroud)
最后一行的输出是 2。
请注意,在ls -l
命令中打印到控制台时,ls不会按原样打印换行符,而是打印?
。但这是ls 的一个专门实现的功能,它在检测到输出将发送到实际终端时执行此操作,以避免有趣的文件名弄乱终端。此相同的检测确定是否文件名打印在每次线(管)或根据终端的宽度(这显然才有意义,如果有是与宽度的端子)。你可以用命令来愚弄ls,就像ls | cat
你想要打印原始文件名,用换行符分隔。
wc -l
只计算行数,如果文件名碰巧包含换行符,那么wc会将其计为两行。
ls也有强制隐藏控制字符的开关,-q
/ --hide-control-chars
,所以ls -q | wc -l
实际上应该给出列出的准确文件数ls
(这通常与目录中的实际文件数不同,没有-a
开关),因为只有ls输出中的换行符应该是那些分隔文件名。