¿Contar archivos en el directorio con una cadena específica en el nombre?

12

Tengo los siguientes archivos:

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

Quiero contar el número de archivos que tienen la palabra snp(mayúsculas y minúsculas) en su nombre. Traté de usar

grep -a 'snp' | wc -l   

pero luego me di cuenta de que grepbusca dentro de los archivos. ¿Cuál es el comando correcto para escanear los nombres de archivo?

Lucia O
fuente
1
¿Has intentado buscar en este sitio "archivos de conteo"?
don_crissti

Respuestas:

18

¿Quiere decir que desea buscar snpen los nombres de archivo ? Eso sería un simple shell glob (comodín), usado así:

ls -dq *snp* | wc -l

Omita la -qbandera si su versión de lsno la reconoce. Maneja nombres de archivo que contienen caracteres "extraños" (incluidas las nuevas líneas).

roaima
fuente
No estaba seguro de si podría usar lspara recuperar nombres de archivo con texto específico en ellos. Eso funcionó, gracias.
Lucia O
@LuciaO vuelve a leer su comentario, no lses que coincida con los nombres de los archivos, es el shell. lsve una lista de archivos que coinciden con el patrón; sí no ver el patrón en sí.
roaima
2
tenga en cuenta que esto podría no funcionar si tiene demasiados archivos regresando.
Dennis Nolte
4

Si te quedas en silencio en los pasillos de Unix y Linux y escuchas con atención, escucharás una voz fantasmal, lamentando, "¿Qué pasa con los nombres de archivo que contienen nuevas líneas?"

ls -d *snp* | wc -l

o, equivalentemente ,

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

generará todos los nombres de archivo que contienen snp, cada uno seguido de una nueva línea, pero también incluirá cualquier nueva línea en los nombres de archivo , y luego contará el número de líneas en la salida. Si hay un archivo cuyo nombre es

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

entonces ese nombre se escribirá como

foosnp
bar.tsv

que, por supuesto, se contarán como dos líneas.

Hay algunas alternativas que funcionan mejor en al menos algunos casos:

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

que cuenta las líneas que contienen snp, por lo que el foosnp(\n)bar.tsvejemplo anterior solo cuenta una vez. Una ligera variación en esto es

ls -f | grep -c snp

Los dos comandos anteriores difieren en que:

  • El ls -fincluirá archivos cuyos nombres comienzan con .; el printf … *no lo hace, a menos que la dotglobopción del shell se establece.
  • printfes una concha incorporada; lsEs un comando externo. Por lo tanto, lspodrían usar un poco más de recursos.
  • Cuando el shell procesa a *, ordena los nombres de archivo; ls -fno ordena los nombres de archivo. Por lo tanto, lspodrían usar un poco menos de recursos.

Pero tienen algo en común: ambos darán resultados incorrectos en presencia de nombres de archivo que contienen nueva línea y tienen snptanto antes como después de la nueva línea .

Otro:

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

Esto crea una variable de matriz de shell que enumera todos los nombres de archivo que contienen snp, y luego informa el número de elementos en la matriz. Los nombres de archivo se tratan como cadenas, no como líneas, por lo que las nuevas líneas incrustadas no son un problema. Es concebible que este enfoque pueda tener un problema si el directorio es enorme, porque la lista de nombres de archivo debe mantenerse en la memoria de shell.

Aún otra:

Anteriormente, cuando dijimos printf "%s\n" *snp*, el printfcomando repitió (reutilizó) la "%s\n"cadena de formato una vez para cada argumento en la expansión de *snp*. Aquí, hacemos un pequeño cambio en eso:

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

Esto repetirá (reutilizará) la "%.0s\n"cadena de formato una vez para cada argumento en la expansión de *snp*. Pero "%.0s"significa imprimir los primeros cero caracteres de cada cadena, es decir, nada. Este printfcomando generará solo una nueva línea (es decir, una línea en blanco) para cada archivo que contenga snpsu nombre; y luego wc -llos contaré. Y, nuevamente, puede incluir los .archivos configurando dotglob.

G-Man dice 'restablecer a Mónica'
fuente
1

Abstracto:

Funciona para archivos con nombres "impares" (incluidas nuevas líneas).

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

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

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

Descripción

Como un globo simple coincidirá con cada nombre de archivo snpen su nombre, un simple echo *snp*podría ser suficiente para este caso, pero para mostrar realmente que solo hay tres archivos coincidentes, usaré:

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

El único problema que queda es contar los archivos. Sí, grep es una solución habitual, y sí, contar nuevas líneas wc -ltambién es una solución habitual. Tenga en cuenta que grep -c(recuento) realmente cuenta cuántas veces snpcoincide una cadena y, si un nombre de archivo tiene más de una snpcadena en el nombre, el recuento será incorrecto.

Podemos hacerlo mejor.

Una solución simple es establecer los argumentos posicionales:

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

Para evitar cambiar los argumentos posicionales, podemos transformar cada argumento en un carácter e imprimir la longitud de la cadena resultante (para la mayoría de los shells):

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

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

O, en bash, para evitar una subshell:

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

Lista de archivos

Lista de archivos (de la pregunta original con una con una nueva línea agregada):

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' 

Eso tendrá un archivo con una nueva línea en el medio:

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

Y para probar la expansión global:

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

Eso agregará un asterisco que, si no está entre comillas, se expandirá a toda la lista de archivos.

NotAnUnixNazi
fuente
-1

supongamos que desea contar la cantidad de archivos html:

ls | grep ".html" | wc -l

así que si estás contando ocurrencias de "snp":

ls | grep "snp" | wc -l
Daniel McGrath
fuente