Contar elementos delimitados por nul en el archivo

8

Tengo un script de shell que se usa find -print0para guardar una lista de archivos para procesar en un archivo temporal. Como parte del registro, me gustaría generar el número de archivos encontrados, por lo que necesito una forma de obtener ese recuento. Si la -print0opción no se usara por seguridad, podría usar wc -lpara obtener el recuento.

qqx
fuente

Respuestas:

11

Algunas opciones:

tr -cd '\0' | wc -c

tr '\n\0' '\0\n' | wc -l      # Generic approach for processing NUL-terminated
                              # records with line-based utilities (that support
                              # NUL characters in their lines like GNU ones).

grep -cz '^'                  # GNU grep

sed -nz '$='                  # recent GNU sed, no output for empty input

awk -vRS='\0' 'END{print NR}' # not all awk implementations

Tenga en cuenta que para una entrada que contiene datos después del último carácter NUL (o entrada no vacía sin caracteres NUL), los trenfoques siempre contarán el número de caracteres NUL, pero los enfoques awk/ sed/ grepcontarán un registro adicional para esos bytes adicionales .

Stéphane Chazelas
fuente
Medí esto en 5 GB de datos aleatorios ( head -c 5G /dev/urandom > f). Resultados: grep 1.7s (lo mismo para grep -Fcz '') • tr + wc-c 7.7s • tr + wc-l 7.4s • sed 34.7s • awk 1m11.7s
Socowi
@Socowi, YMMV con la implementación y la configuración regional. Con GNU awk, querrá establecer la configuración regional en C(o cualquiera que no use caracteres multibyte),LC_ALL=C awk ... < f
Stéphane Chazelas
Gracias por la pista. Ya utilizado LC_ALL=Cen sortdonde no acelerar las cosas, por lo tanto Afortunadamente todavía tengo tener el archivo de delante: LC_ALL=C awk ...toma 6.7s.
Socowi
4

El mejor método en el que he podido pensar es usar grep -zc '.*'. Esto funciona, pero se siente mal usar grep con un patrón que coincida con cualquier cosa.

qqx
fuente
1

Con perl:

perl -0ne 'END {print $.}'

o:

perl -nle 'print scalar split "\0"'

o:

perl -nle 'print scalar unpack "(Z*)*", $_'
Cuonglm
fuente
El primero contará un registro adicional si hay datos después del último NUL. Los otros 2 no funcionan si la entrada contiene caracteres de nueva línea.
Stéphane Chazelas
@ StéphaneChazelas: Oh, mi mal. ¿Podrías dar alguna mejora?
Cuonglm
Simplemente me quedaría con el primero y mencionaría el hecho de que cuenta un registro no delimitado (contrario a wc -l) como una nota (como puede ser que se quiera).
Stéphane Chazelas