Liste des fichiers triés par le nombre de lignes qu'ils contiennent

32

Comment puis-je lister le nombre de lignes dans les fichiers /group/book/four/word, triés par le nombre de lignes qu'ils contiennent?

ls -l commande les répertorie mais ne les trie pas

Ken R
la source
1
Souhaitez-vous que les fichiers soient répertoriés par nombre de lignes, ou que vous en indiquiez le nombre ou les deux? ls -lne donne pas le nombre de lignes. ls -lStrie le fichier par taille avec certaines lsimplémentations (la taille étant le nombre d'octets dans le contenu).
Stéphane Chazelas

Réponses:

34

Vous devriez utiliser une commande comme celle-ci:

find /group/book/four/word/ -type f -exec wc -l {} + | sort -rn
  • find: rechercher des fichiers sur le chemin que vous voulez. Si vous ne le souhaitez pas et que votre findimplémentation le prend en charge, vous devez l'ajouter -maxdepth 1juste avant l' -execoption.
  • exec: indique à la commande à exécuter wc -lsur chaque fichier.
  • sort -rn: trier les résultats numériquement dans l’ordre inverse. De plus en plus bas.

(cela suppose que les noms de fichiers ne contiennent pas de caractères de nouvelle ligne).

Jherran
la source
Notez que lorsqu'il est passé plus d'un fichier (ou avec certaines implémentations, plus d'un fichier qu'il peut lire), wcimprimera également une totalligne, donc ici vous aurez aussi une ou plusieurs lignes "totales" à moins qu'il n'y ait qu'un seul fichier . Vous pouvez diriger pour grep /les supprimer.
Stéphane Chazelas
Vote positif à cause du sortcommandement
Francisco
comment puis-je filtrer pour afficher uniquement les fichiers avec X lignes minimum (exclure X = 0 ligne par exemple)?
Matrix
11

Non récursif

Probablement la version la plus simple si vous n'avez pas besoin de récursivité:

wc -l /group/book/four/word/*|sort -n

wccompte les lignes (option -l) dans tous les *fichiers (mais cachés) ( ) sous /group/book/four/word/, et sorttrie le résultat (par le biais du canal |) numériquement (option -n).

Récursif

Quelqu'un a commenté cette réponse grep -rlcavant de la supprimer. En effet, grepc’est une excellente alternative, surtout si vous avez besoin de récursivité:

grep -rc '^' /group/book/four/word/|tr ':' ' '|sort -n -k2

comptera (option -c) récursivement (option -r) lignes correspondantes ( grep) '^'(c'est-à-dire, début de lignes) dans le répertoire /group/book/four/word/. Ensuite, vous devez remplacer les deux points par un espace, par exemple en utilisant tr, pour aider sort, que vous souhaitez trier numériquement (option -n) sur la deuxième colonne (option -k2).

Mise à jour: Voir le commentaire de Stéphane sur les limitations possibles et sur la façon de s'en débarrasser tr.

Skippy le Grand Gourou
la source
3
grep -c .compte les lignes qui contiennent au moins un caractère valide. Utilisez grep -c '^'pour compter toutes les lignes (comptera également les caractères de fin après la dernière nouvelle ligne avec certaines grepimplémentations). Notez que toutes les grepimplémentations ne prennent pas en charge le -rcomportement a et varie selon les utilisateurs. Vous n'avez pas besoin de traduire :s (deux points, pas de point-virgule) en espaces pour sort. Il suffit d'utiliser -t:. Notez que cela suppose que les noms de fichiers ne contiennent pas de caractères :vides ou de nouvelle ligne.
Stéphane Chazelas
1
Merci d’avoir posté votre solution non récursive; Je ne savais pas avoir wcdonné un total aussi pratique si vous passiez par plusieurs chemins. Coupler cette fonctionnalité avec le joker et le tuyau sortest vraiment propre.
Qcom
7

Avec zsh:

lines() REPLY=$(wc -l < $REPLY)
printf '%s\n' /group/book/four/word/*(.no+lines)

Nous définissons une nouvelle fonction de trilines qui répond avec le nombre de lignes du fichier. Et nous utilisons le o+linesqualificatif glob qui, avec n(pour le tri numérique), définit la manière dont les résultats du glob sont ordonnés. ( .également ajouté pour vérifier uniquement les fichiers normaux).

Cela ne fait aucune hypothèse sur le caractère que les noms de fichier peuvent contenir, à part les fichiers cachés (ceux commençant par .) qui sont omis. Ajoutez le Dqualificatif glob si vous le souhaitez également.

Stéphane Chazelas
la source
2
OP est marqué avec bashseulement ...
l0b0
7
@ l0b0 cela ne signifie pas que la prochaine personne qui en aura besoin exécutera également bash.
terdon
4

Vous ne spécifiez pas si vous voulez également les fichiers dans les sous-répertoires de /group/book/four/word. La findsolution dans la réponse de jherran descendra dans les sous-répertoires. Si cela n'est pas souhaité, utilisez plutôt le shell:

for file in ./*; do [ -f "$file" ] && wc -l "$file"; done | sort -n

Si vos noms de fichier peuvent contenir des nouvelles lignes, vous pouvez utiliser quelque chose comme:

for file in ./*; do 
    [ -f "$file" ] && 
        printf "%lu %s\0" "$(wc -l < "$file")" "$file"
done | sort -zn | tr '\0' '\n'

Enfin, si vous faites défaut de descendre dans les sous - répertoires, vous pouvez l' utiliser dans bash4 ou au- dessus:

shopt -s globstar
for file in ./**/*; do [ -f "$file" ] && wc -l "$file"; done | sort -n

Notez que les versions de bashavant 4.3 suivaient les liens symboliques lors récursive en descendant l'arborescence (comme zsh« s ou tcshd » ***/*).

En outre, toutes les solutions ci-dessus ignoreront les fichiers cachés (ceux dont le nom commence par un ., utilisez-les shopt -s dotglobpour les inclure) et incluront également le nombre de lignes de liens symboliques (ce que l' findapproche ne permettra pas).

terdon
la source
Notez que la différence entre la solution de jherran et celle de jherran est que le vôtre considérera également le lien symbolique vers les fichiers normaux ( -xtype fdans GNU find ou *(-.)dans zsh) et omettra les fichiers cachés.
Stéphane Chazelas
@ StéphaneChazelas merci, clarifions. Pourquoi le %ludans printf? Si je me souviens bien, cela signifie une longue décimale non signée, est-ce vraiment nécessaire? Pourquoi ne pas traiter le nombre comme une chaîne? Est-ce que cela fait une différence?
terdon
2
Si la sortie wc est vide (par exemple parce que le fichier n'est pas lisible), 0la chaîne sera étendue à la place de la chaîne vide, ce qui est légèrement meilleur. Certaines implémentations de tri fonctionnent avec des entiers non signés, d'autres avec des signatures. %luCela semble être le pari le plus sûr, mais cela n’a probablement pas d’importance, comme si vous aviez des 2^31lignes, cela prendra de toute façon des siècles.
Stéphane Chazelas
1

Si vous voulez installer fdun outil de recherche de fichiers très rapide écrit en Rust (vous devez l’installer, c’est génial d’avoir de toute façon)

fd --type=file . | xargs wc -l | sort -n

En gros, fdliste les fichiers, xargs passera la liste des fichiers à wc(signifie nombre de mots mais passage -l le fera compter les lignes), puis finalement trié du plus petit nombre de lignes à la plus grande sort -n.

JustGage
la source