Buscando una manera de eliminar líneas en blanco desde el principio y el final (usando tac
) de un archivo, me topé con esta:
awk 'NF {p=1} p'
¿Cómo/por qué funciona esto?
Lo entiendo NF
solo true
si hay campos (si la línea no es una línea en blanco).
Respuesta1
Esto eliminará las líneas en blanco desde el principio,pero no desde el finalde un archivo.[Aviso: esta respuesta fue escrita antes deleditar a la preguntaque mencionó tac
]
Funciona de la siguiente manera:
NF
es el número de campos encontrados en la línea actual. Si es cero, eso significa que la línea está vacía oblanco, es decir, contiene como máximo espacios en blanco (asumiendo que el separador de campo se deja en su valor predeterminado, donde cualquier número de espacios en blanco consecutivos se considera como separador).- La línea actual se imprime si alguna condición fuera de (y no asociada con) los bloques de reglas (
{ ... }
) se evalúa comotrue
. Inicialmente , la banderap
no está inicializada y se evaluará comofalse
, por lo que a priori no se imprimirá nada. - Una vez que se encuentra una línea que no está en blanco (
NF
no es cero y se evalúa como ), se ingresatrue
al bloque de reglas y se establece el indicador en . Después de eso, el exterior del bloque de reglas se evalúa como y se imprimen las líneas posteriores (incluida la actual, la primera que no está en blanco).{p=1}
p
1
p
true
Avisoque dado que la bandera p
nunca se restablece, cualquier línea en blanco que venga después de la primera línea que no esté en blanco se imprimirá sin filtrar. Si también desea eliminar las líneas en blanco del final, será necesario un método de dos pasadas:
awk 'FNR==NR{if (NF) {if (!first) first=FNR; last=FNR} next}
FNR>=first && FNR<=last' input.txt input.txt
Esto procesará el archivo dos veces (por lo tanto, se especifica dos veces como operando)
- En la primera pasada, donde
FNR
el contador de líneas por archivo es igual aNR
el contador de líneas global, identificamos la primera y la última línea que no están en blanco. - En la segunda pasada (
FNR
ahora es más pequeña queNR
), solo imprimimos líneas entre (e incluyendo) la primera y la última línea no en blanco así identificadas.
Aviso
Como se indica en elrespuesta de Stéphane Chazelas, el método de dos pasadas sólo funciona con archivos normales. Si su aportación es de naturaleza diferente, consulte el método propuesto allí para encontrar una solución.
Respuesta2
Usando esta técnica para eliminar líneas en blanco tanto del principio como del final del archivo:
awk 'NF {p=1} p' file | # remove blank lines at the file head
tac | # reverse the lines
awk 'NF {p=1} p' | # remove blanks from the "new head"
tac | # re-reverse the file
sponge file # from the `moreutils` package, to overwrite the file
Respuesta3
Lo que hace su código y por qué solo elimina líneas en blanco al comienzo de la entrada ya se ha explicado enLa respuesta de @AdminBeepor ejemplo, pero aquí para completar, sugeriré un método alternativo para eliminar las líneas en blanco iniciales y finales sin tener que hacer dos pasadas en el archivo (lo que solo funcionaría para archivos normales y no para entradas arbitrarias).
awk '
NF {print saved $0; saved = ""; started = 1; next}
started {saved = saved $0 ORS}' < file
Donde retrasamos la impresión de líneas en blanco hasta la siguiente línea que no está en blanco que vemos después (siempre que ya hayamos visto al menos una línea que no esté en blanco antes).
Respuesta4
En caso de que no le importe colocar espacios o tabulaciones en las líneas en blanco que desea conservar, esto eliminará las líneas en blanco del principio y del final:
awk 'NF{for(;c;--c)print "";print;x=1;next} x{++c}'
Cuenta cuántas líneas en blanco aparecen entre líneas que no están en blanco e imprime esa cantidad de líneas vacías antes de cada línea que no está en blanco.