Compter les fichiers dans le répertoire avec une chaîne spécifique sur le nom?

12

J'ai les fichiers suivants:

Codigo-0275_tdim.matches.tsv  
Codigo-0275_tdim.snps.tsv  
FloragenexTdim_haplotypes_SNp3filter17_single.tsv  
FloragenexTdim_haplotypes_SNp3filter17.tsv  
FloragenexTdim_SNP3Filter17.fas  
S134_tdim.alleles.tsv    
S134_tdim.snps.tsv  
S134_tdim.tags.tsv

Je veux compter le nombre de fichiers qui ont le mot snp(sensible à la casse) sur leur nom. J'ai essayé d'utiliser

grep -a 'snp' | wc -l   

mais j'ai réalisé que les greprecherches dans les fichiers. Quelle est la bonne commande pour parcourir les noms de fichiers?

Lucia O
la source
1
Avez-vous essayé de rechercher des «fichiers de comptage» sur ce site?
don_crissti

Réponses:

18

Voulez-vous dire que vous souhaitez rechercher snpdans les noms de fichiers ? Ce serait un simple shell glob (joker), utilisé comme ceci:

ls -dq *snp* | wc -l

Omettez le -qdrapeau si votre version de lsne le reconnaît pas. Il gère les noms de fichiers contenant des caractères "étranges" (y compris les retours à la ligne).

roaima
la source
Je n'étais pas sûr de pouvoir utiliser lspour récupérer les noms de fichiers contenant du texte spécifique. Cela a fonctionné cependant, merci.
Lucia O
@LuciaO relisant votre commentaire, ce n'est pas lsqui correspond aux noms de fichiers, c'est le shell. lsvoit une liste de fichiers correspondant au modèle; il ne voit pas le motif lui-même.
roaima
2
notez que cela peut ne pas fonctionner si vous avez renvoyé trop de fichiers.
Dennis Nolte
4

Si vous vous tenez tranquillement dans les couloirs d'Unix et Linux et écoutez attentivement, vous entendrez une voix fantomatique, gémissant pitoyablement, «Et les noms de fichiers qui contiennent des sauts de ligne?»

ls -d *snp* | wc -l

ou, de manière équivalente ,

printf "%s\n" *snp* | wc -l

affichera tous les noms de fichiers qui contiennent snp, chacun suivi d'un retour à la ligne, mais également tous les retours à la ligne dans les noms de fichiers , puis comptera le nombre de lignes dans la sortie. S'il existe un fichier dont le nom est

                                f o o s n p \n b a r . t s v

alors ce nom sera écrit comme

foosnp
bar.tsv

qui, bien sûr, comptera pour deux lignes.

Il existe quelques alternatives qui font mieux dans au moins certains cas:

printf "%s\n" * | grep -c snp

qui compte les lignes qui contiennent snp, donc l' foosnp(\n)bar.tsvexemple ci-dessus ne compte qu'une seule fois. Une légère variation à ce sujet est

ls -f | grep -c snp

Les deux commandes ci-dessus diffèrent en ce que:

  • Le ls -fcomprendra des fichiers dont les noms commencent par .; ce printf … *n'est pas le cas, sauf si l' dotgloboption shell est définie.
  • printfest un shell intégré; lsest une commande externe. Par conséquent, le lspeut utiliser un peu plus de ressources.
  • Lorsque le shell traite a *, il trie les noms de fichiers; ls -fne trie pas les noms de fichiers. Par conséquent, le lspeut utiliser un peu moins de ressources.

Mais ils ont quelque chose en commun: ils donneront tous les deux des résultats erronés en présence de noms de fichiers qui contiennent un retour à la ligne et qui ont à la snpfois avant et après le retour à la ligne .

Un autre:

filenamelist=(*snp*)
echo ${#filenamelist[@]}

Cela crée une variable de tableau shell répertoriant tous les noms de fichiers qui contiennent snp, puis signale le nombre d'éléments dans le tableau. Les noms de fichiers sont traités comme des chaînes, pas comme des lignes, donc les sauts de ligne intégrés ne sont pas un problème. Il est concevable que cette approche puisse avoir un problème si le répertoire est énorme, car la liste des noms de fichiers doit être conservée dans la mémoire du shell.

Encore un autre:

Plus tôt, lorsque nous l'avons dit printf "%s\n" *snp*, la printfcommande a répété (réutilisé) la "%s\n"chaîne de formatage une fois pour chaque argument dans l'expansion de *snp*. Ici, nous faisons un petit changement:

printf "%.0s\n" *snp* | wc -l

Cela va répéter (réutiliser) la "%.0s\n"chaîne de formatage une fois pour chaque argument dans l'expansion de *snp*. Mais "%.0s"signifie imprimer les premiers caractères zéro de chaque chaîne - c'est-à-dire rien. Cette printfcommande ne produira qu'une nouvelle ligne (c'est-à-dire une ligne vierge) pour chaque fichier qui contient snpson nom; puis wc -lles comptera. Et, encore une fois, vous pouvez inclure les .fichiers en définissant dotglob.

G-Man dit «Réintègre Monica»
la source
1

Abstrait:

Fonctionne pour les fichiers avec des noms "impairs" (y compris les nouvelles lignes).

set -- *snp* ; echo "$#"                             # change positional arguments

count=$(printf 'x%.0s' *snp*); echo "${#count}"      # most shells

printf -v count 'x%.0s' *snp*; echo "${#count}"      # bash

La description

Comme un simple glob correspondra à chaque nom de fichier avec snpdans son nom, un simple echo *snp*pourrait suffire dans ce cas, mais pour vraiment montrer qu'il n'y a que trois fichiers correspondant, je vais utiliser:

$ ls -Q *snp*
"Codigo-0275_tdim.snps.tsv"  "foo * bar\tsnp baz.tsv"  "S134_tdim.snps.tsv"

Le seul problème qui reste est de compter les fichiers. Oui, grep est une solution habituelle, et oui, compter de nouvelles lignes avec wc -lest également une solution habituelle. Notez que grep -c(count) compte vraiment combien de fois une snpchaîne est mise en correspondance et, si un nom de fichier a plus d'une snpchaîne dans le nom, le nombre sera incorrect.

On peut faire mieux.

Une solution simple consiste à définir les arguments positionnels:

$ set -- *snp*
$ echo "$#"
3

Pour éviter de changer les arguments positionnels, nous pouvons transformer chaque argument en un caractère et afficher la longueur de la chaîne résultante (pour la plupart des shells):

$ printf 'x%.0s' *snp*
xxx

$ count=$(printf 'x%.0s' *snp*); echo "${#count}"
3

Ou, en bash, pour éviter un sous-shell:

$ printf -v count 'x%.0s' *snp*; echo "${#count}"
3

Liste des fichiers

Liste des fichiers (de la question d'origine avec un avec une nouvelle ligne ajoutée):

a='
Codigo-0275_tdim.matches.tsv
Codigo-0275_tdim.snps.tsv
FloragenexTdim_haplotypes_SNp3filter17_single.tsv
FloragenexTdim_haplotypes_SNp3filter17.tsv
FloragenexTdim_SNP3Filter17.fas
S134_tdim.alleles.tsv
S134_tdim.snps.tsv
S134_tdim.tags.tsv'
$ touch $a

touch $'foosnp\nbar.tsv' 

Cela aura un fichier avec une nouvelle ligne au milieu:

f o o s n p \n b a r . t s v

Et pour tester l'expansion globale:

$ touch $'foo * bar\tsnp baz.tsv'

Cela ajoutera un astérisque qui, s'il n'est pas cité, s'étendra à toute la liste des fichiers.

Isaac
la source
-1

disons que vous vouliez compter le nombre de fichiers html:

ls | grep ".html" | wc -l

donc si vous comptez les occurrences de "snp":

ls | grep "snp" | wc -l
Daniel McGrath
la source