Si je le fais ls -1 target_dir | wc -l
, j'obtiens un nombre de fichiers dans un répertoire. Je trouve cela un peu lourd. Existe-t-il une manière plus élégante ou succincte?
ubuntu
command-line
filesystems
codecowboy
la source
la source
ls
donne déjà le nombre total, alors pourquoi pasls -l | head -1
? Faites-en un alias si vous voulez quelque chose de plus court.ls -l
indique la taille totale des fichiers, pas le nombre de fichiers.ls | wc -l
cela vous donnera le mauvais nombre si des noms de fichiers contiennent des retours à la ligne.stat -c %h .
donne les mêmes informations quels -ld . | cut -d" " -f 2
Réponses:
En supposant que bash 4+ (que possède toute version prise en charge d'Ubuntu):
Appelez-le comme
num_files [dir]
.dir
est facultatif, sinon il utilise le répertoire courant. Votre version d'origine ne compte pas les fichiers cachés, donc cela non plus. Si vous le voulez,shopt -s dotglob
avantset -- *
.Votre exemple d'origine compte non seulement les fichiers normaux, mais aussi les répertoires et autres périphériques - si vous ne voulez vraiment que des fichiers normaux (y compris des liens symboliques vers des fichiers normaux), vous devrez les vérifier:
Si vous avez GNU find, quelque chose comme ça est également une option (notez que cela inclut les fichiers cachés, ce que votre commande d'origine n'a pas fait):
(changement
-type
de-xtype
si vous voulez aussi compter les liens symboliques vers des fichiers réguliers).la source
set
s'il y a beaucoup de fichiers? Je pense que vous pourriez avoir à utiliserxargs
et un code de sommation pour que cela fonctionne dans le cas général.shopt -s dotglob
si vous voulez que les fichiers commençant par.
soient comptésset
cela échouera dans ces circonstances, car nous ne faisons pas réellement deexec
. À savoir, sur mon système,getconf ARG_MAX
donne 262144, mais si je le faistest_arg_max() { set -- {1..262145}; echo $#; }; test_arg_max
, il répond volontiers 262145.-maxdepth
n'est pas POSIX.f=(target_dir/*);echo ${#f[*]}
fonctionne correctement pour le fichier avec des espaces, des retours à la ligne, etc. dans le nom.
la source
ls
est multi-colonnes uniquement s'il sort directement sur un terminal, vous pouvez supprimer l'option "-1", vous pouvez supprimer l'wc
option "-l", ne lire que la première valeur (solution paresseuse, ne pas utiliser pour les preuves légitimes, enquêtes criminelles, missions critiques, opérations tactiques ..).la source
wc
pour obtenir le nombre de fichiers même dans le cas trivial, alors comment est-ce même une solution?target
s'agit d'un glob qui, une fois développé, inclut des éléments commençant par des tirets. Par exemple, créez un nouveau répertoire, allez-y et faitestouch -- {1,2,3,-a}.txt && ls *|wc
(NB: utilisezrm -- *.txt
pour supprimer ces fichiers.)wc -l
? Sinon, vous obtenez le nombre de sauts de ligne, de mots et d'octets de lals
sortie. C'est ce que David Richerby a dit: Vous devez à nouveau l'analyser.wc
sans argument que vous n'avez pas besoin d'analyser si votre cerveau sait que le premier argument est un retour à la ligne.Si ce que vous êtes de succinctness après (plutôt que la correction exacte à laquelle le traitement des dossiers avec des sauts de ligne dans leurs noms, etc.), je recommande simplement d' aliasing
wc -l
àlc
( « nombre de lignes »):Comme d'autres l'ont remarqué, vous n'avez pas besoin de cette
-1
optionls
, car elle est automatique lors de l'ls
écriture dans un tuyau. (Sauf si vous avez unls
alias pour toujours utiliser le mode colonne. J'ai déjà vu cela, mais pas très souvent.)Un
lc
alias est assez pratique en général, et pour cette question, si vous regardez le cas "compter le répertoire courant", ills|lc
est aussi succinct que possible.la source
Jusqu'à présent, Aaron est la seule approche plus succincte que la vôtre. Une version plus correcte de votre approche pourrait ressembler à ceci:
Cela répertorie récursivement tous les fichiers - pas les répertoires - un par ligne, y compris .dotfiles sous le répertoire actuel, en utilisant des globes shell au besoin pour remplacer les caractères non imprimables. grep filtre toutes les listes de répertoires parents ou .. ou * / ou les lignes vides - il ne doit donc y avoir qu'une seule ligne par fichier - le nombre total dont grep vous renvoie. Si vous souhaitez également inclure les répertoires enfants:
Supprimez le
-R
dans les deux cas si vous ne souhaitez pas de résultats récursifs.la source
find
. Si vous ne voulez qu'un décompte, cela devrait fonctionner:find -mindepth 1 -maxdepth 1 -printf '\n'|wc -l
(supprimez les contrôles de profondeur pour obtenir des résultats récursifs).find . \! -name . -prune | wc -l
- ce qui ne fonctionne toujours pas, bien sûr.printf
instruction affiche une chaîne constante (une nouvelle ligne) qui n'inclut pas du tout le nom de fichier, donc les résultats sont indépendants de tout nom de fichier étrange. Cette astuce ne peut pas être faite du tout avec unfind
qui ne prend pas en chargeprintf
, bien sûr.find .//. \!. -name . -prune | grep -c '^\.//\.'
/
étant le seul autre caractère qui ne peut pas apparaître dans les noms de fichiers, la.//.
séquence est garantie d'apparaître exactement une fois pour chaque fichier, non? quelques questions cependant - pourquoi.//.
et pourquoi-prune
? quand cela différerait-ilfind . \! -name . | grep -c '^\.'
? (Je suppose que le.
dans votre\!.
est une faute de frappe.)