Cuente el número de líneas en blanco al final del archivo

11

Tengo un archivo con líneas en blanco al final del archivo. ¿Puedo usar greppara contar el número de líneas en blanco al final del archivo con el nombre del archivo que se pasa como variable en el script?

Raghunath Choudhary
fuente
contar el número de líneas en blanco consecutivas ?
RomanPerekhrest
2
@RomanPerekhrest Yo diría que si no, ¿no estarían "al final del archivo"?
Sparhawk
'grep -cv -P' \ S 'filename' contará el número total de líneas en blanco en el archivo. ¡El número al final solo está gravando mi cerebro!
MichaelJohn
OP solicitó que grep@MichaelJohn gane por pureza en mi libro.
bu5hman
2
@ bu5hman Pero (como él admite) no responde la pregunta. Tampoco el tuyo, de verdad.
Sparhawk

Respuestas:

11

Si las líneas en blanco son solo al final

grep  -c '^$' myFile

o:

grep -cx '' myFile
bu5hman
fuente
Golpeado a la edición por segundos, maldita sea
bu5hman
grep -cv . myFilees otra forma de escribirlo (para golfistas de código). Pero encontré una solución con grepsi hay líneas vacías en cualquier parte del archivo.
Philippos
2
@Philippos, grep -cv .también contaría las líneas que contienen solo bytes que no forman caracteres válidos.
Stéphane Chazelas
11

Solo por diversión, algunos espeluznantes sed:

#!/bin/sh
sed '/./!H;//h;$!d;//d;x;s/\n//' "$1" | wc -l

Explicación:

  • /./direcciona líneas con cualquier carácter, de modo que /./!aborda líneas no vacías; para aquellos, el Hcomando los agrega al espacio de espera. Por lo tanto, si para cada línea vacía hemos agregado una línea al espacio de espera, siempre hay una línea más que el número de líneas vacías. Nos ocuparemos de eso más tarde.
  • //hel patrón vacío coincide con la última expresión regular, que era cualquier carácter, por lo que cualquier línea no vacía se direcciona y se mueve al espacio de espera mediante el hcomando para "restablecer" las líneas recopiladas a 1. Cuando se agregue la siguiente línea vacía, Habrá dos de nuevo, como se esperaba.
  • $!ddetiene el script sin salida para todas las líneas excepto la última, por lo que los comandos adicionales solo se ejecutan después de la última línea. Entonces, las líneas vacías que recolectamos en el espacio de espera están al final del archivo. Bueno.
  • //d: El dcomando se ejecuta nuevamente solo para líneas no vacías. Entonces, si la última línea no estaba vacía, sedsaldrá sin ningún resultado. Líneas cero Bueno.
  • x Los intercambios contienen espacio y espacio de patrón, por lo que las líneas recopiladas están ahora en el espacio de patrón para ser procesadas.
  • Pero recordamos que hay una sola línea demasiado, así que la reducimos eliminando una nueva línea con s/\n//.
  • Voilà! El número de líneas coincide con el número de líneas vacías al final (tenga en cuenta que la primera línea no estará vacía, pero a quién le importa), por lo que podemos contar con ellas wc -l.
Philippos
fuente
8

Algunas opciones más de GNU tac/ tail -r:

tac file | awk 'NF{exit};END{print NR?NR-1:0}'

O:

tac file | sed -n '/[^[:blank:]]/q;p' | wc -l

Tenga en cuenta que en la salida de:

printf 'x\n '

Es decir, donde hay un espacio adicional después de la última línea completa (que algunos podrían considerar como una línea en blanco adicional, pero según la definición POSIX de texto, no es texto válido), esos darían 0.

POSIXY:

awk 'NF{n=NR};END{print NR-n}' < file

pero eso significa leer el archivo completo ( tail -r/ tacleería el archivo hacia atrás desde el final en archivos buscables). Eso da 1en la salida de printf 'x\n '.

Stéphane Chazelas
fuente
6

Como en realidad está pidiendo una grepsolución , agrego esta confiando solo en GNU grep(está bien, también usando la sintaxis de shell y echo...):

#!/bin/sh
echo $(( $(grep -c "" "$1") - $(grep -B$(grep -cv . "$1") . "$1" |grep -c "") ))

¿Qué estoy haciendo aquí? $(grep -c ".*" "$1")cuenta todas las líneas en el archivo, luego restamos el archivo sin las líneas vacías finales.

¿Y cómo conseguirlos? $(grep -B42 . "$1"grep todas las líneas no vacías y 42 líneas antes de ellas, por lo que imprimiría todo hasta la última línea no vacía, siempre que no haya más de 42 líneas vacías consecutivas antes de una línea no vacía. Para evitar ese límite, tomo $(grep -cv . "$1")como parámetro para la -Bopción, que es el número total de líneas vacías, por lo que siempre es lo suficientemente grande. De esta manera, he eliminado las líneas vacías finales y puedo usar |grep -c ".*"para contar las líneas.

Brillante, ¿no es así? (-;

Philippos
fuente
+1 porque, aunque es un código horrible, técnicamente responde a la pregunta tal como se le preguntó y no puedo soportar marcarlo ;-)
roaima
Grepmeister No somos dignos
bu5hman
+1 para la perversidad. Otra opción (¿posiblemente más rápida?) Sería tac | grepla primera que no esté en blanco con -m -A 42, luego menos una. No estoy seguro de cuál es más eficiente, pero ¿también podría en wc -l | cut -d' ' -f1lugar de grep las líneas en blanco?
Sparhawk
Sí, claro, puedes hacer muchas cosas con tac, wcy cut, pero aquí intenté restringirme grep. Puedes llamarlo perversidad, yo lo llamo deportes. (-;
Philippos
5

Otra awksolucion. Esta variación restablece el contador kcada vez que hay una línea no en blanco. Luego, cada línea incrementa el contador. (Entonces, después de la primera línea de longitud no en blanco,. k==0) Al final, mostramos el número de líneas que hemos contado.

Prepara el archivo de datos

cat <<'X' >input.txt
aaa

bbb
ccc



X

Cuente las líneas en blanco al final de la muestra

awk 'NF {k=-1}; {k++}; END {print k+0}' input.txt
3

En esta definición, una línea en blanco puede contener espacios u otros caracteres en blanco; Todavía está en blanco. Si realmente desea contar líneas vacías en lugar de líneas en blanco, cambie NFpor $0 != "".

roaima
fuente
¿Por qué $0 > ""? Eso usa lo strcoll()que sería menos eficiente que lo $0 != ""que usa memcmp()en muchas implementaciones (POSIX solía requerir que lo usara strcoll()).
Stéphane Chazelas
@ StéphaneChazelas No he considerado que $0 > ""podría ser diferente a $0 != "". De awktodos modos, tiendo a tratar como un operador "lento" (de modo que si sé que tengo un gran conjunto de datos como entrada y el procesamiento es crítico en el tiempo, veré qué puedo hacer para reducir la cantidad que awktiene que procesar - I han usado grep | awkconstrucciones en tales situaciones). Sin embargo, después de haber tenido un rápido vistazo a lo que supongo que es la definición del estándar POSIX no puedo ver ninguna referencia ni a strcoll()o memcmp(). ¿Qué me estoy perdiendo?
roaima
strcoll()== las cadenas se compararán utilizando la secuencia de clasificación específica de la localidad . Compare con la edición anterior . Yo fui quien lo mencionó. Ver también austingroupbugs.net/view.php?id=963
Stéphane Chazelas
@ StéphaneChazelas una implementación donde a <= b && a >= bno es necesariamente lo mismo que a == b. ¡Ay!
roaima
Ese es el caso de GNU awko bash(por sus [[ a < b ]]operadores) en en_US.UTF-8 lugares en los sistemas GNU, por ejemplo para la frente , por ejemplo, (a bash, ninguno de <, >, =devolver cierto para aquellos). Podría decirse que es un error en la definición de esos locales más que en bash / awk
Stéphane Chazelas
2

para contar el número de líneas en blanco consecutivas al final del archivo

Solución sólida awk+ tac:

Muestra input.txt:

$ cat input.txt
aaa

bbb
ccc



$  # command line 

La acción:

awk '!NF{ if (NR==++c) { cnt++ } else exit }END{ print int(cnt) }' <(tac input.txt)
  • !NF- asegura que la línea actual esté vacía (no tiene campos)
  • NR==++c- Asegurar el orden consecutivo de líneas en blanco. ( NR- número de registro, ++c- contador auxiliar uniformemente incrementado)
  • cnt++- contador de líneas en blanco

La salida:

3
RomanPerekhrest
fuente
1

IIUC, el siguiente script llamado count-blank-at-the-end.shharía el trabajo:

#!/usr/bin/env sh

count=$(tail -n +"$(grep . "$1" -n | tail -n 1 | cut -d: -f1)" "$1" | wc -l)
num_of_blank_lines=$((count - 1))

printf "%s\n" "$num_of_blank_lines"

Ejemplo de uso:

$ ./count-blank-at-the-end.sh FILE
4

Lo probé en GNU bash, Android mkshy en ksh.

Arkadiusz Drabczyk
fuente