web-dev-qa-db-fra.com

Pourquoi "ls | wc -l" affiche-t-il le nombre correct de fichiers dans le répertoire actuel?

En essayant de compter le nombre de fichiers dans le répertoire courant, j'ai trouvé ls -1 | wc -l, ce qui signifie: envoyer la liste des fichiers (où chaque nom de fichier est imprimé sur une nouvelle ligne) à l'entrée de wc, où -l comptera le nombre de lignes en entrée. C'est logique.

J'ai décidé d'essayer simplement ls | wc -l et j'en ai été très surpris me donne également un nombre correct de fichiers. Je me demande pourquoi cela se produit, car la commande ls sans options affiche les noms de fichiers sur une seule ligne.

42
Kirill

De info ls:

'-1'
'- format = simple colonne'

Répertoriez un fichier par ligne. Il s'agit de la valeur par défaut pour 'ls' lorsque la sortie standard n'est pas un terminal.

Lorsque vous dirigez la sortie de ls, vous obtenez un nom de fichier par ligne.
ls ne produit les fichiers en colonnes que lorsque la sortie est destinée aux yeux humains.


Voici où ls décide quoi faire:

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

source: http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/ls.c

57
glenn jackman

Parce que la sortie de ls dépend de la sortie std, elle est différente pour terminal et pipe. Essayer

/bin/ls | cat
14
jimmij

Historiquement, ls écrivait sa sortie un fichier par ligne, qui est un format pratique pour le traitement avec d'autres outils Unix basés sur du texte (comme wc). Cependant, sur un terminal de 24 lignes sans défilement, les grandes listes avaient tendance à défiler hors de l'écran, ce qui rend difficile de trouver ce que vous cherchiez. Donc, à un moment donné, les développeurs BSD ont changé le comportement donc, lors de l'impression sur un terminal, ls formaterait sa sortie en plusieurs colonnes. L'ancien comportement a été conservé lors de l'écriture dans un canal ou un fichier pour éviter de casser les scripts Shell existants --- et parce que l'ancien comportement est plus utile lors du traitement de la sortie avec une commande comme wc. Les décisions d'incorporer la sortie multi-colonnes dans ls et d'en faire la valeur par défaut sur le terminal, exercé un peu Rob Pike ; Research Unix n'a pas récupéré les nouvelles fonctionnalités avant la 8e édition (qui était directement basée sur BSD) et le plan 9 est revenu à des commandes distinctes, ls pour les scripts et lc pour une utilisation interactive, avec lc un script Shell appelant ls et une commande mc fournissant une sortie multi-colonnes.

Le -1 et -C les options de ls sont une tentative tardive de restaurer la raison, en permettant au moins à l'utilisateur de forcer un format de sortie spécifique quelle que soit la destination de sortie.

10
Jonathan Cast

Pourquoi "ls | wc -l ”affiche le nombre correct de fichiers dans le répertoire actuel?

Eh bien, c'est une fausse prémisse ici. Ce ne est pas! Essaye ça:

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

La sortie de cette dernière ligne est 2.

Notez comment, lors de l'impression sur la console dans ls -l commande, ls n'imprimera pas la nouvelle ligne telle quelle, mais imprimera à la place ?. Mais ceci est une fonctionnalité spécifiquement implémentée de ls, il le fait quand il détecte que la sortie va vers un terminal réel, pour éviter que des noms de fichiers amusants gâchent le terminal. Cette même détection détermine si les noms de fichiers sont imprimés une par ligne (dans le tube) ou selon la largeur du terminal (ce qui n'a évidemment de sens que s'il y a is un terminal avec une largeur). Vous pouvez tromper ls avec une commande comme ls | cat si vous voulez que les noms de fichiers bruts soient imprimés, séparés par des retours à la ligne.

wc -l compte juste le nombre de lignes, et si un nom de fichier contient une nouvelle ligne, alors wc le comptera comme deux lignes.


ls a également des commutateurs pour forcer le masquage des caractères de contrôle, -q/--hide-control-chars, donc ls -q | wc -l devrait en fait donner un nombre précis de fichiers répertoriés par ls (qui n'est généralement pas le même que le nombre réel de fichiers dans le répertoire, sans -a switch), car alors seuls les retours à la ligne dans la sortie ls devraient être ceux qui séparent les noms de fichiers.

7
hyde