为什么“ls | wc -l”显示当前目录中的文件数量正确?

Kir*_*ill 44 ls wc

试图计算当前目录中的文件数,我发现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

  • 你会想阅读关于`isatty()` (8认同)

jim*_*mij 15

因为输出ls取决于 std 输出,所以终端和管道是不同的。尝试

/bin/ls | cat
Run Code Online (Sandbox Code Playgroud)


Jon*_*ast 11

从历史上看,ls每行写入一个文件,这是使用其他基于文本的 Unix 工具(如wc)进行处理的一种方便格式。但是,在没有回滚的 24 行终端上,大型列表倾向于滚出屏幕,从而很难找到您要查找的内容。因此,在某些时候,BSD 开发人员改变了行为,以便在打印到终端时ls将其输出格式化为多列。在写入管道或文件时保留旧行为以避免破坏现有的 shell 脚本 --- 并且因为旧行为在使用类似wc. 将多列输出合并ls到终端上并将其设为默认值的决定,相当多地锻炼了 Rob Pike;Research Unix 直到第 8 版(直接基于 BSD)才采用新功能,Plan 9 恢复为单独的命令,ls用于脚本和lc交互式使用,具有lcshell 脚本调用lsmc提供多列输出的命令。

-1-C选项ls都恢复神智,至少允许用户强制一个特定的输出格式,无论输出目的地迟来的尝试。


hyd*_*yde 7

为什么“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输出中的换行符应该是那些分隔文件名。