Comment lister le nombre de lignes de chaque fichier dans un répertoire dans un format lisible par l'homme.

41

J'ai une liste de répertoires et de sous-répertoires contenant de gros fichiers CSV. Il y a environ 500 millions de lignes dans ces fichiers, chacun étant un enregistrement. J'aimerais savoir

  1. Combien de lignes sont dans chaque fichier.
  2. Combien de lignes sont dans le répertoire.
  3. Combien de lignes au total

Plus important encore, j'ai besoin de cela dans un «format lisible par l'homme», par exemple. 12 345 678 plutôt que 12345678

Ce serait bien d'apprendre à faire cela de 3 façons. Plain vanilla bash tools, awk etc., et perl (ou python).

Hexatonique
la source

Réponses:

57

Combien de lignes sont dans chaque fichier.

Utilisez wc, à l'origine pour le nombre de mots, je crois, mais il peut faire des lignes, des mots, des caractères, des octets et la plus grande longueur de ligne. L' -loption lui dit de compter les lignes.

wc -l <filename>

Cela produira le nombre de lignes dans:

$ wc -l /dir/file.txt
32724 /dir/file.txt

Vous pouvez également diriger des données vers wc:

$ cat /dir/file.txt | wc -l
32724
$ curl google.com --silent | wc -l
63

Combien de lignes sont dans le répertoire.

Essayer:

find . -name '*.pl' | xargs wc -l

un autre one-liner:

( find ./ -name '*.pl' -print0 | xargs -0 cat ) | wc -l

En passant, la wccommande compte les nouvelles lignes, pas les lignes. Lorsque la dernière ligne du fichier ne se termine pas par un nouveau code de ligne, cela ne compte pas.

Vous pouvez utiliser grep -c ^, exemple complet:

#this example prints line count for all found files
total=0
find /path -type f -name "*.php" | while read FILE; do
     #you see use grep instead wc ! for properly counting
     count=$(grep -c ^ < "$FILE")
     echo "$FILE has $count lines"
     let total=total+count #in bash, you can convert this for another shell
done
echo TOTAL LINES COUNTED:  $total

Combien de lignes au total

Pas sûr que j'ai bien compris votre demande. par exemple, cela produira les résultats au format suivant, en indiquant le nombre de lignes pour chaque fichier:

# wc -l `find /path/to/directory/ -type f`
 103 /dir/a.php
 378 /dir/b/c.xml
 132 /dir/d/e.xml
 613 total

Sinon, il peut s'avérer utile de ne générer que le nombre total de caractères de nouvelle ligne sans compter le nombre de fichiers par fichier jusqu'à la commande suivante:

# find /path/to/directory/ -type f -exec wc -l {} \; | awk '{total += $1} END{print total}'
 613

Plus important encore, j'ai besoin de cela dans un «format lisible par l'homme», par exemple. 12 345 678 plutôt que 12345678

Bash a une fonction printf intégrée dans:

printf "%0.2f\n" $T

Comme toujours, de nombreuses méthodes différentes pourraient être utilisées pour obtenir les mêmes résultats que ceux mentionnés ici.

Malyy
la source
Au fait, comment utiliser printf dans vos exemples? J'ai essayé d'y accéder depuis wc -l, mais cela n'a pas fonctionné.
Hexatonic
essayer> trouver. -name '* .pl' | xargs wc -l | awk '{printf ("% 0.2f", $ 1)} {print $ 2}' modifie le résultat de 'printf' pour vos besoins
mardi
Cela n'ajoute pas de virgule au nombre pour le rendre plus lisible par l'homme. Il ajoute simplement des zéros à la fin.
Hexatonic
echo 1000000000000 | xargs printf "% 'd \ n" 1 000 000 000 000
Hexatonic le
1
@Hexatonic printfne lit pas ses arguments depuis stdin, mais plutôt depuis la ligne de commande (comparez piping à echovs piping à cat; catlit à partir de stdin, echone lit pas). Utilisez plutôt printf "$(find ... | xargs ...)"pour fournir la sortie en tant qu'arguments à printf.
BallpointBen
13

Dans de nombreux cas, la combinaison de la wccommande et du caractère générique *peut suffire.
Si tous vos fichiers sont dans un seul répertoire, vous pouvez appeler:

wc -l src/*

Vous pouvez également lister plusieurs fichiers et répertoires:

wc -l file.txt readme src/* include/*

Cette commande affichera une liste des fichiers et leur nombre de lignes.
La dernière ligne sera la somme des lignes de tous les fichiers.


Pour compter tous les fichiers d’un répertoire de manière récursive:

Tout d’abord, activez globstar en ajoutant shopt -s globstarà votre fichier .bash_profile. La prise en charge de globstar nécessite Bash ≥ 4.x qui peut être installé avec brew install bashsi nécessaire. Vous pouvez vérifier votre version avec bash --version.

Puis lancez:

wc -l **/*

Notez que cette sortie sera incorrecte si globstar n’est pas activé.

Thomio
la source
Et pour compter les fichiers dans le répertoire courant de façon récursive:wc -l **/*
Taylor Edmiston
@TaylorEdmiston Pour moi (sur Mac), cela ne compte que les fichiers avec un seul répertoire. Il ignore les fichiers du répertoire en cours et, dans tous les cas où il y aurait plus d'un répertoire, il avertit qu'il s'agit d'un répertoire: " wc: parent_dir/child_dir: read: Is a directory"
M. Justin le
@Thomio Il faut que globstar soit activé. Sur macOS, je pense qu’il est désactivé par défaut. Je viens d’envoyer une modification à votre réponse qui ajoute la commande et comment activer Globstar.
Taylor Edmiston
2

Cette commande donnera une liste de code de lignes dans chaque répertoire:

find . -name '*.*' -type f | xargs wc -l
Suresh.A
la source
2

un peu tard pour le jeu, mais j'ai eu un tas d'erreurs d'argument avec ce qui précède en raison de la taille du répertoire. Cela a fonctionné pour moi:

for i in $(find . -type f); do wc -l $i; done >> /home/counts.txt

Ron Paulfan
la source
0

catcombinerait les fichiers en un seul et sortirait le tout sur stdout, vous pouvez faire wc -lcela pour un nombre total de lignes de fichiers dans un répertoire:

cat /path/to/directory/* | wc -l
picmate 涅
la source
0

Je vais juste augmenter la réponse @malyy pour le suivant (trop grand pour un commentaire):

Combien de lignes au total

Beaucoup de réponses utilisent l' wcoption de fichier en ligne de commande avec xargs. Le problème, c’est que xargs se limite à une taille de plate-forme relativement petite.

De plus, il existe une différence entre BSD (macOS) et GNU (linux / homebrew) wc.

GNU est idéal car il peut lire la liste de fichiers à partir d’un fichier au lieu d’arguments ( --files0).

Si vous êtes sur mac et avez homebrew, vous devriez faire ce qui suit:

find . -name "*.pl" -print0 | gwc -l --files0=-

Remarquez le gwc au lieu de wc .

Adam Gent
la source