Contare i file nella directory con una stringa specifica sul nome?


12

Ho i seguenti file:

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

Voglio contare il numero di file che hanno la parola snp(case sensitive) sul loro nome. Ho provato a usare

grep -a 'snp' | wc -l   

ma poi ho capito che le grepricerche all'interno dei file. Qual è il comando corretto per scansionare i nomi dei file?


1
Hai provato a cercare in questo sito "contare i file"?
don_crissti,

Risposte:


18

Vuoi dire che vuoi cercare snpnei nomi dei file ? Sarebbe un semplice shell glob (jolly), usato in questo modo:

ls -dq *snp* | wc -l

Ometti la -qbandiera se la tua versione di lsnon la riconosce. Gestisce nomi di file contenenti caratteri "strani" (comprese le nuove righe).


Non ero sicuro di poter utilizzare lsper recuperare i nomi dei file con testo specifico al loro interno. Ha funzionato però, grazie.
Lucia O,

@LuciaO rilegge il tuo commento, non lsè che corrisponda ai nomi dei file, è la shell. lsvede un elenco di file corrispondenti allo schema; essa non vedere il modello stesso.
roaima,

2
si noti che potrebbe non funzionare se si restituiscono troppi file.
Dennis Nolte,

4

Se ti trovi in ​​silenzio nei corridoi di Unix e Linux e ascolti attentamente, sentirai una voce spettrale, che geme pietosamente, "E i nomi di file che contengono nuove righe?"

ls -d *snp* | wc -l

o, equivalentemente ,

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

produrrà tutti i nomi dei file che contengono snp, ciascuno seguito da una nuova riga, ma includendo anche le eventuali nuove righe nei nomi dei file , quindi conterà il numero di righe nell'output. Se esiste un file il cui nome è

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

allora quel nome sarà scritto come

foosnp
bar.tsv

che, ovviamente, verranno conteggiati come due righe.

Ci sono alcune alternative che fanno meglio in almeno alcuni casi:

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

che conta le righe che contengono snp, quindi l' foosnp(\n)bar.tsvesempio di cui sopra conta solo una volta. Una leggera variazione su questo è

ls -f | grep -c snp

I due comandi precedenti differiscono in quanto:

  • La ls -fincluderà i file i cui nomi iniziano con .; il printf … *non fa a meno che l' dotglobopzione di shell è impostata.
  • printfè una shell incorporata; lsè un comando esterno. Pertanto, lspotrebbero utilizzare leggermente più risorse.
  • Quando la shell elabora a *, ordina i nomi dei file; ls -fnon ordina i nomi dei file. Pertanto, lspotrebbe utilizzare leggermente meno risorse.

Ma hanno qualcosa in comune: entrambi daranno risultati sbagliati in presenza di nomi di file che contengono newline e avranno snpsia prima che dopo la nuova riga .

Un altro:

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

Questo crea una variabile di array di shell che elenca tutti i nomi di file che contengono snpe quindi riporta il numero di elementi nell'array. I nomi dei file sono trattati come stringhe, non linee, quindi le nuove righe incorporate non rappresentano un problema. È ipotizzabile che questo approccio possa avere un problema se la directory è enorme, perché l'elenco dei nomi dei file deve essere conservato nella memoria della shell.

Ancora un altro:

In precedenza, quando abbiamo detto printf "%s\n" *snp*, il printfcomando ha ripetuto (riutilizzato) la "%s\n"stringa di formato una volta per ogni argomento nell'espansione di *snp*. Qui, facciamo un piccolo cambiamento in questo:

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

Questo ripeterà (riutilizzerà) la "%.0s\n"stringa di formato una volta per ogni argomento nell'espansione di *snp*. Ma "%.0s"significa stampare i primi zero caratteri di ogni stringa, ovvero niente. Questo printfcomando produrrà solo una nuova riga (cioè una riga vuota) per ogni file che contiene snpnel suo nome; e poi wc -lli conterà. E, ancora una volta, puoi includere i .file impostando dotglob.


1

Astratto:

Funziona con file con nomi "dispari" (incluse nuove righe).

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

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

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

Descrizione

Poiché un semplice glob corrisponderà a ogni nome di file con snpnel suo nome, un semplice echo *snp*potrebbe essere sufficiente per questo caso, ma per mostrare davvero che ci sono solo tre file corrispondenti userò:

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

L'unico problema rimasto è il conteggio dei file. Sì, grep è una solita soluzione, e sì contare anche nuove righe wc -lè una solita soluzione. Si noti che grep -c(count) conta davvero quante volte snpviene abbinata una stringa e, se un nome di file ha più di una snpstringa nel nome, il conteggio sarà errato.

Possiamo fare di meglio.

Una soluzione semplice è impostare gli argomenti posizionali:

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

Per evitare di modificare gli argomenti posizionali, possiamo trasformare ogni argomento in un carattere e stampare la lunghezza della stringa risultante (per la maggior parte delle shell):

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

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

Oppure, in bash, per evitare una subshell:

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

Elenco dei file

Elenco di file (dalla domanda originale con uno con una nuova riga aggiunta):

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' 

Che avrà un file con una nuova riga nel mezzo:

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

E per testare l'espansione glob:

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

Ciò aggiungerà un asterisco, che, se non quotato, si espanderà all'intero elenco di file.


-1

diciamo che volevi contare il numero di file html:

ls | grep ".html" | wc -l

quindi se stai contando le occorrenze di "snp":

ls | grep "snp" | wc -l
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.