¿Eliminar números de línea específicos de un archivo de texto usando sed?
-
22-09-2019 - |
Pregunta
Quiero eliminar uno o más números de línea específicos de un archivo.¿Cómo haría esto usando sed?
Solución
Si quiere borrar las líneas 5 a 10 y de 12:
sed -e '5,10d;12d' file
Esto imprimirá los resultados en la pantalla. Si desea guardar los resultados en el mismo archivo:
sed -i.bak -e '5,10d;12d' file
Esto copia el archivo hasta file.bak
y eliminar las líneas dadas.
Nota:. Los números de línea comienzan en 1. La primera línea del archivo es 1, no 0
Otros consejos
Puede eliminar una sola línea particular con su número de línea por sed -i '33d' archivo
Esto eliminará la línea en 33 el número de línea y guardar el archivo actualizado.
y awk así
awk 'NR!~/^(5|10|25)$/' file
$ cat foo
1
2
3
4
5
$ sed -e '2d;4d' foo
1
3
5
$
Esto es muy a menudo un síntoma de un anti patrón. La herramienta que produjo los números de línea bien puede ser reemplazado con uno que elimina las líneas de inmediato. Por ejemplo;
grep -nh error logfile | cut -d: -f1 | deletelines logfile
(donde deletelines
es la utilidad que se está imaginando que necesita) es el mismo que
grep -v error logfile
Una vez dicho esto, si se encuentra en una situación en la que realmente necesita para llevar a cabo esta tarea, se puede generar una secuencia de comandos sed
sencilla desde el archivo de números de línea. Con humor (pero quizás un poco confusa) se puede hacer esto con sed
.
sed 's%$%d%' linenumbers
Esta acepta un archivo de números de línea, una por línea, y produce, en la salida estándar, los mismos números de línea con d
añaden después de cada. Este es un script válido sed
, que podemos guardar en un archivo, o (en algunas plataformas) tubería a otra instancia sed
:
sed 's%$%d%' linenumbers | sed -f - logfile
En algunas plataformas, sed -f
no entender la -
argumento de opción en el sentido de la entrada estándar, así que hay que redirigir la secuencia de comandos en un archivo temporal, y limpiarlo cuando haya terminado, o quizás reemplazar el tablero solitario con /dev/stdin
o /proc/$pid/fd/1
si su sistema operativo (o cáscara) tiene eso.
Como siempre, se puede añadir la opción -i
antes -f
tener sed
editar el archivo de destino en su lugar, en vez de producir el resultado en la salida estándar. En las plataformas * BSDish (incluyendo OS X) es necesario proporcionar un argumento explícito para -i
así; un lenguaje común es la de suministrar un argumento vacío; -i ''
.
Me gustaría proponer una generalización con awk.
Cuando el archivo se realiza mediante bloques de un tamaño fijo y las líneas para eliminar se repiten para cada bloque, AWK puede funcionar bien de tal manera
awk '{nl=((NR-1)%2000)+1; if ( (nl<714) || ((nl>1025)&&(nl<1029)) ) print $0}'
OriginFile.dat > MyOutputCuttedFile.dat
En este ejemplo, el tamaño del bloque es 2000 y quiero imprimir las líneas [1..713] y [1026..1029].
NR
es la variable utilizada por awk para almacenar el número de línea actual.%
da el resto (o módulo) de la división de dos números enteros;nl=((NR-1)%BLOCKSIZE)+1
Aquí escribimos en la variable nl el número de línea dentro del bloque actual.(vea abajo)||
y&&
son el operador lógico O y Y.print $0
escribe la línea completa
Why ((NR-1)%BLOCKSIZE)+1:
(NR-1) We need a shift of one because 1%3=1, 2%3=2, but 3%3=0.
+1 We add again 1 because we want to restore the desired order.
+-----+------+----------+------------+
| NR | NR%3 | (NR-1)%3 | (NR-1)%3+1 |
+-----+------+----------+------------+
| 1 | 1 | 0 | 1 |
| 2 | 2 | 1 | 2 |
| 3 | 0 | 2 | 3 |
| 4 | 1 | 0 | 1 |
+-----+------+----------+------------+