Por que “ls | wc -l ”mostra o número correto de arquivos no diretório atual? [duplicado]

37

Tentando contar o número de arquivos no diretório atual, encontrei ls -1 | wc -l , o que significa: enviar a lista de arquivos (onde cada nome de arquivo é impresso em uma nova linha) para a entrada de wc, onde -l contará o número de linhas na entrada. Isso faz sentido.

Eu decidi tentar simplesmente ls | wc -l e fiquei muito surpreso com isso e também me dá um número correto de arquivos. Eu me pergunto por que isso acontece, porque o comando ls sem opções imprime os nomes dos arquivos em uma única linha.

    
por Derp 24.09.2014 / 18:12

4 respostas

53

De info ls :

'-1'
'--format=single-column'

List one file per line. This is the default for 'ls' when standard output is not a terminal.

Quando você canaliza a saída de ls , você obtém um nome de arquivo por linha.
ls somente exibe os arquivos em colunas quando a saída é destinada aos olhos humanos.

Aqui é onde ls decide o que fazer:

  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 ();
    }

fonte: link

    
por 24.09.2014 / 18:25
14

Como a saída de ls depende da saída padrão, ela é diferente para terminal e tubo. Experimente

/bin/ls | cat
    
por 24.09.2014 / 18:26
10

Historicamente, ls escreveu sua saída um arquivo por linha, que é um formato conveniente para processamento com outras ferramentas Unix baseadas em texto (como wc ). No entanto, em um terminal de 24 linhas sem rolagem, listas grandes tinham a tendência de rolar para fora da tela, dificultando a localização do que você estava procurando. Então, em algum momento, os desenvolvedores do BSD alteraram o comportamento e, ao imprimir em um terminal, ls formaria sua saída em várias colunas. O comportamento antigo era mantido ao gravar em um pipe ou arquivo para evitar a quebra de scripts de shell existentes - e porque o comportamento antigo é mais útil ao processar a saída com um comando como wc . As decisões de incorporar a saída de várias colunas em ls e torná-la padrão no terminal, exercitado Rob Pike um pouco ; A Research Unix não pegou os novos recursos até a 8ª Edição (que foi baseada diretamente no BSD) e o Plan 9 reverteu para comandos separados, ls para scripts e lc para uso interativo, com lc uma chamada de script de shell ls e um comando mc fornecendo saída de várias colunas.

As opções -1 e -C para ls são uma tentativa tardia de restaurar a sanidade, ao permitir pelo menos que o usuário force um formato de saída específico, independentemente do destino de saída.

    
por 24.09.2014 / 23:33
6

Why does “ls | wc -l” show the correct number of files in current directory?

Bem, essa é uma falsa premissa bem aqui. Isso não! Tente isto:

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

A saída dessa última linha é 2.

Observe como, ao imprimir no console no comando ls -l , ls não imprimirá a nova linha como está, mas imprimirá ? . Mas este é um recurso especificamente implementado de ls , ele faz isso quando detecta que a saída está indo para um terminal real, para evitar que nomes de arquivos engraçados atrapalhem o terminal. Essa mesma detecção determina se os nomes dos arquivos são impressos um por linha (no pipe) ou de acordo com a largura do terminal (o que obviamente só faz sentido se houver um terminal com largura). Você pode enganar ls com o comando como ls | cat se quiser que os nomes dos arquivos brutos sejam impressos, separados por novas linhas.

wc -l apenas conta o número de linhas, e se um nome de arquivo contiver uma nova linha, então wc contará como duas linhas.

ls também possui opções para forçar o ocultamento de caracteres de controle, -q / --hide-control-chars , portanto ls -q | wc -l deve fornecer o número exato de arquivos listados por ls (que geralmente não é o mesmo como número real de arquivos no diretório, sem -a switch), porque, então, apenas as novas linhas na saída ls devem ser aquelas que separam os nomes dos arquivos.

    
por 25.09.2014 / 12:54

Tags