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.