Comment utiliser wc et piping pour trouver le nombre de fichiers et de répertoires dans un certain répertoire?

10

Comment puis-je utiliser le compteur de mots ( wc) et la tuyauterie pour compter le nombre de fichiers ou de répertoires dans le /usr/binrépertoire?

en espèces
la source
Ces devoirs ?? C'est OK de demander de l'aide, identifiez-le comme tel, si c'est le cas.
slm
oui, mais je poste ici pour avoir une idée sur la façon de réaliser quelque chose, car je suis nouveau sur Linux et cela peut être très compliqué. Et je résout déjà la question ci-dessus avec cette commande
cash
ls / bin / usr / bin | trier | uniq | wc -
espèces
np. C'est très bien de demander de l'aide! Étiquetez-le simplement pour que les gens sachent, tout le monde ici est généralement heureux d'aider les gens qui essaient d'apprendre les points les plus fins d'Unix.
slm

Réponses:

13

Une approche consisterait à utiliser lspour nous donner une liste des fichiers, mais nous voulons que cette liste soit garantie de ne montrer qu'un seul fichier ou répertoire par ligne. L' -1interrupteur fera cela pour nous.

$ ls -1
dir1
dir2
dir3
fileA
fileB
fileC

Exemple

Créez les exemples de données ci-dessus dans un répertoire vide.

$ mkdir dir{1..3}
$ touch file{A..C}

Vérifie ça:

$ ls
dir1  dir2  dir3  fileA  fileB  fileC

Maintenant, pour compter, vous pouvez utiliser wc -lpour compter le nombre de lignes, qui correspondent à un fichier ou un répertoire dans la ls -1sortie.

$ ls -1 | wc -l
6

(notez cependant qu'il n'inclut pas les fichiers cachés)

Compter des fichiers ou des répertoires, mais pas ensemble

Pour compter les fichiers ou les répertoires, vous devez modifier légèrement votre tactique. Dans ce cas, j'utiliserais ls -lcar il montre ce qu'est un répertoire et ce qu'est un fichier.

Exemple

$ ls -l
total 12
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir1
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir2
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir3
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileA
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileB
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileC

Ensuite, nous pouvons utiliser greppour filtrer les répertoires ou non-répertoires comme ceci:

# directories
$ ls -l | grep "^d"
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir1
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir2
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir3

# regular files
$ ls -l | grep "^-"
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileA
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileB
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileC

Maintenant, utilisez à wc -lnouveau pour compter ce qui précède:

# directories
$ ls -l | grep "^d" | wc -l
3

# regular files
$ ls -l | grep "^-" | wc -l
3

Cependant, vous pouvez éviter wccomplètement et utiliser grepl' -coption de:

$ ls -l | grep -c '^d'

(encore une fois, les fichiers cachés ne sont pas inclus. Notez que les répertoires et regular sont deux types de fichiers. Il y en a beaucoup plus comme des canaux nommés, des liens symboliques, des périphériques, des sockets ...).

Récursivité

Si vous devez trouver les fichiers et les répertoires de manière récursive sous, /usr/binvous voudrez probablement changer complètement de tactique et utiliser un autre outil appelé find.

Exemple

$ find /usr/bin | wc -l
4632

(même si au /usr/bin- dessus de lui - même est inclus dans le décompte)

Les mêmes techniques que j'ai utilisées ci-dessus pourraient être utilisées lspour faire quelque chose de similaire, mais ce lsn'est généralement pas un bon outil pour analyser la sortie. findd'autre part, a été conçu pour cela et propose des commutateurs pour rechercher des fichiers ou des répertoires.

# find files
$ find /usr/bin -type f

# find directories
$ find /usr/bin -type d

(notez que cette fois, findinclut les fichiers cachés (sauf .et ..)).

nouvelles lignes?

Je n'ai jamais compris pourquoi un caractère de nouvelle ligne est un caractère légal à utiliser lors de la création de noms de fichiers ou de répertoires. Donc, les méthodes décrites ci-dessus les utilisent wcet lsne les contesteraient pas, alors utilisez-les dans cet esprit.

Exemple

Créez un répertoire et un nom de fichier avec des retours à la ligne.

$ mkdir $'dir4\n5'
$ touch $'fileD\nE'

ls les montre correctement:

$ ls -1
dir1
dir2
dir3
dir4?5
fileA
fileB
fileC
fileD?E

Mais wccompte les répertoires et les fichiers qui contiennent des sauts de ligne comme 2 éléments, pas un.

$ ls -1 | wc -l
10

Une méthode pour contourner ce problème, si vous utilisez l'implémentation GNU de, findest d'utiliser findla capacité de pour imprimer quelque chose d'autre à la place de chaque fichier qu'il trouve, puis les compter à la place.

Exemple

$ find . -printf . | wc -c
9

Ici , nous tout ce constat êtes la dans le répertoire courant (sauf ..), et l' impression d' un point ( .) pour chacun, puis compter les points en utilisant wcla capacité de » count octets au lieu de lignes, wc -c.

Références

slm
la source
Bien que les fichiers /usr/binsoient tous bien formatés (et ne contiendront pas non plus d'espaces, donc techniquement vous pourriez même juste echo * | wc -w), il convient de noter que tous ces éléments se briseront sur les noms de fichiers contenant des sauts de ligne.
evilsoup
@evilsoup - non je ne crois pas ls -lou ls -1va casser b / c on compte les lignes, pas les mots! Le findpeut casser, mais encore une fois, nous comptons des lignes et non des mots.
slm
Ce que je veux dire, c'est que cela (je pense, je suis sur Windows en ce moment donc je ne peux pas tester) se casser si les fichiers contiennent des sauts de ligne . Donc, touch $'foo\nbar'dans un répertoire vide suivi par l'une de vos commandes (disons ls -1 | wc -l), vous rapporterez deux fichiers plutôt qu'un - car ce fichier est de deux lignes en ce qui wcconcerne. À moins de lsremplacer les nouvelles lignes par un autre personnage (je ne pense pas, mais encore une fois je ne suis pas en mesure de tester pour le moment).
evilsoup
@evilsoup - correct, caractère de nouvelle ligne. est un caractère légal. pour les noms de fichiers, et les méthodes ne pourraient pas gérer correctement ces types de noms de fichiers.
slm
@StephaneChazelas - est wc -cun problème lors du comptage des périodes?
slm
5

Si vous voulez obtenir une ventilation du nombre de chaque type de fichier récursivement sous un certain répertoire, avec GNU find, vous pouvez faire:

find /some/dir/. ! -name . -printf '%y\n' | sort | uniq -c | sed '
  s/f/regular files/;t
  s/d/directories/;t
  s/l/symbolic links/;t
  s/s/Unix domain sockets/;t
  s/b/block devices/;t
  s/c/character devices/;t
  s/p/FIFOs/;t
  s/D/Doors/;t
  s/n/network special files/;t
  s/.$/others (&)/'

Sur /usr/binmon système, cela donne:

   3727 regular files
    710 symbolic links

Le /dev:

     83 block devices
    203 character devices
     31 directories
    426 symbolic links
      1 FIFOs
      1 Unix domain sockets

Pour les liens symboliques, si vous préférez les compter comme le type de fichier vers lequel ils pointent plutôt que symbolic links, vous pouvez le changer en:

find /some/dir/. ! -name . -printf '%Y\n' | sort | uniq -c | sed '
  s/f/regular files/;t
  s/d/directories/;t
  s/N/broken symbolic links/;t
  s/s/Unix domain sockets/;t
  s/b/block devices/;t
  s/c/character devices/;t
  s/p/FIFOs/;t
  s/D/Doors/;t
  s/n/network special files/;t
  s/.$/others (&)/'

Ce qui donne maintenant pour mon /usr/bin:

      1 directories
   4434 regular files
      2 broken symbolic links

(un lien symbolique rompu est un lien symbolique vers un fichier dont findle type ne peut pas être déterminé soit parce que le fichier n'existe pas, soit dans un répertoire auquel vous n'avez pas accès ou qu'il y a une boucle dans la résolution du chemin du fichier Dans mon cas, ces 2 où les liens symboliques vers des fichiers qui ont maintenant disparu).

Aucun de ceux-là ne compte .et ... Si vous vouliez les inclure (pourquoi le feriez-vous?), Il n'y a pas d'autre moyen findque de supposer qu'ils sont là pour chaque répertoire et de les compter systématiquement:

find /some/dir/. -printf '%y\n' \( -name . -printf 'd\n' -o \
  -type d -printf 'd\nd\n' \)  | sort | uniq -c | sed '
  s/f/regular files/;t
  s/d/directories/;t
  s/l/symbolic links/;t
  s/s/Unix domain sockets/;t
  s/b/block devices/;t
  s/c/character devices/;t
  s/p/FIFOs/;t
  s/D/Doors/;t
  s/n/network special files/;t
  s/.$/others (&)/'

Ce qui donne alors sur mon /usr/bin:

      2 directories
   3727 regular files
    710 symbolic links

Si vous n'avez pas accès au GNU find, vous pouvez réécrire le premier comme:

find /some/dir/. ! -name . \( \
  -type f -exec printf '%.0sregular files\n' {} + -o \
  -type d -exec printf '%.0sdirectories\n' {} + -o \
  -type l -exec printf '%.0ssymbolic links\n' {} + -o \
  -type s -exec printf '%.0sUnix domain sockets\n' {} + -o \
  -type b -exec printf '%.0sblock devices\n' {} + -o \
  -type c -exec printf '%.0scharacter devices\n' {} + -o \
  -type p -exec printf '%.0sFIFOs\n' {} + -o \
  -exec printf '%.0sothers\n' {} + \) | sort | uniq -c

Maintenant, à proprement parler, nous ne comptons pas les fichiers mais les entrées de répertoire . Un répertoire comme /usr/bingénéralement possède plusieurs entrées qui pointent vers le même fichier. Par exemple, ici, j'ai:

$ ls -lid /usr/bin/{nvi,nview,nex}
672252 -rwxr-xr-x 3 root root 434616 May 25 07:40 /usr/bin/nex
672252 -rwxr-xr-x 3 root root 434616 May 25 07:40 /usr/bin/nvi
672252 -rwxr-xr-x 3 root root 434616 May 25 07:40 /usr/bin/nview

Ce sont 3 entrées de répertoire (aka noms de fichiers aka liens durs) dans le même fichier (celui avec inode 672252. Pour compter les fichiers au lieu des entrées de répertoire et avec GNU findet GNU uniq(ignorant .et ..fichiers qui de toute façon sont des liens durs vers d' autres répertoires):

find /some/dir/. ! -name . -printf '%y\t%D:%i\n' |
  sort -u |
  cut -f1 |
  uniq -c |
  sed '
    s/f/regular files/;t
    s/d/directories/;t
    s/l/symbolic links/;t
    s/s/Unix domain sockets/;t
    s/b/block devices/;t
    s/c/character devices/;t
    s/p/FIFOs/;t
    s/d/Doors/;t
    s/n/network special files/;t
    s/.$/others (&)/'

Sur mon /usr/bin, cela donne:

   3711 regular files
    710 symbolic links
Stéphane Chazelas
la source
0

Vous n'avez pas dit si vous voulez que tout le fichier se trouve sous / usr / bin récursivement ou juste sous le premier niveau. Aussi, comment allez-vous obtenir les mots que vous comptez? La manière habituelle de le découvrir est d'exécuter find dans wc. Comme ceci: trouver / usr / bin | wc -l Find répertorie tout ce qui s'y trouve, répertoires et fichiers. Wc -l comptera toutes les lignes dans la sortie de recherche. Est-ce un devoir de classe? Ce n'est pas grave si c'est le cas, mais je me demandais pourquoi vous aviez besoin de ces informations pour que je puisse adapter la réponse plus soigneusement. Veuillez me faire savoir si vous en avez besoin de plus. Costa

cdr
la source
0

En bash, sans outils externes.

cd dir/ || exit; shopt -s nullglob; shopt -s dotglob; count=(*); echo "${#count}"

En bash, sans outils externes et récursivité.

shopt -s globstar; shopt -s dotglob 
for dir in **/*/; do 
  unset d f
  for files in "$dir"*; do 
    [[ -f $files ]] && ((++f))
    [[ -d $files ]] && ((++d))
  done; 
  printf '%s\n' "$dir -  files: ${f:-0} - directories: ${d:-0}"
done
llua
la source
Notez que le second suivrait les liens symboliques lors de la récursivité (et compterait les liens symboliques vers des fichiers normaux comme des fichiers normaux et les liens symboliques vers des répertoires comme des répertoires), ne compterait pas les fichiers et les répertoires du répertoire actuel et ne compterait .ni les ..entrées. Vous voudrez peut-être lever l'ambiguïté du fichier par rapport au fichier normal.
Stéphane Chazelas