¿Cómo puedo editar las últimas n líneas en un archivo?

10

¿Hay algún comando que me permita editar las últimas n líneas en un archivo? Tengo varios archivos, todos tienen un número diferente de líneas dentro. Pero me gustaría modificar las últimas n líneas en cada archivo. El objetivo es reemplazar las comas con punto y coma en las últimas n líneas. Pero solo en las últimas n líneas.

No quiero eliminar ninguna línea, solo quiero reemplazar cada coma con un punto y coma en las últimas n líneas de cada archivo.

Usando el comando sed, puedo reemplazar la última línea con este comando. Como se describe aquí: ¿Cómo puedo eliminar texto en la última línea de un archivo?

Pero esto solo me permite modificar la última línea, y no la última n cantidad de líneas.

sku2003
fuente
1
Simplemente usando sed '24,$s/,/:/g' filename where 24is the start line`
Valentin Bajrami

Respuestas:

13

Para reemplazar comas con punto y coma en las últimas n líneas con ed:

n=3
ed -s input <<< '$-'$((n-1))$',$s/,/;/g\nwq'

Dividiendo eso aparte:

  • ed -s = ejecutar ed en silencio (no informar los bytes escritos al final)
  • '$-'= desde el final del archivo ( $) menos ...
  • $((n-1)) = n-1 líneas ...
  • ( $' ... '= cita el resto del comando para protegerlo del shell)
  • ,$s/,/;/g= ... hasta el final del archivo ( ,$), busque y reemplace todas las comas con punto y coma.
  • \nwq = finalizar el comando anterior, luego guardar y salir

Para reemplazar comas con punto y coma en las últimas n líneas con sed:

n=3
sed -i "$(( $(wc -l < input) - n + 1)),\$s/,/;/g" input

Rompiendo eso aparte:

  • -i = editar el archivo "en el lugar"
  • $(( ... )) = hacer algunas matemáticas:
  • $( wc -l < input) = obtener el número de líneas en el archivo
  • -n + 1 = retroceder líneas n-1
  • ,\$ = desde n-1 líneas hasta el final del archivo:
  • s/,/;/g = reemplazar las comas con punto y coma.
Jeff Schaller
fuente
Se puede reemplazar wc -l < inputcon wc -l input. Debería ser más rápido por unos pocos nanosegundos :)
gardenhead
1
excepto que también wc -l inputgenera el nombre de archivo; solo queremos el recuento de líneas
Jeff Schaller
El primer consejo con ed es bueno y simple.
sku2003
En realidad terminé recibiendo ayuda de un lado completamente diferente. Esto dio como resultado este extraño fragmento de código, que funciona pero es largo y extraño. Supongo que estas son algunas de las cosas raras con las que puedes terminar cuando se trata de armar una solución. De todos modos, el tuyo es más bonito, más corto y menos complicado que el mío: el código aquí también funcionó:
sku2003
cat input.file | sed 's /, /, \ n / g' | sed -n '1! G; h; $ p' | awk -vn = 2 'NR <= n {gsub (",", ";", $ 0)} {print}' | sed -n '1! G; h; $ p' | sed '/ ^ \ s * $ / d'> output.file
sku2003
6

Solución usando tac y sed para reemplazar cada coma con un punto y coma en las últimas 50 líneas de file.txt:

tac file.txt | sed '1,50s/,/;/g' | tac
Gohu
fuente
5

Con GNU heady un shell tipo Bourne:

n=20
{ head -n -"$n"; tr , ';'; } < file 1<> file

Estamos sobrescribiendo el archivo sobre sí mismo. Eso está bien aquí por una transliteración byte a byte, pero no necesariamente si la modificación implica cambiar el tamaño del archivo (en cuyo caso, habría que desee reemplazar 1<> filecon > other-file && mv other-file file, por ejemplo).

Stéphane Chazelas
fuente
1
Aquí hay documentos para los1<> que no estaba familiarizado. Además, spongedesde moreutils es una buena herramienta para las tuberías donde desea sobrescribir su entrada.
Millas
1

Supongamos que queremos reemplazar las últimas 7líneas de la siguiente secuencia con script de shell e implementación GNU de sed:

$ seq 20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Paso 1 : obtengamos el número de secuencia de la última línea como el siguiente. Echa un vistazo a esto y aquello :

$ lastLine=`seq 20|sed -n '$='`

$ echo $lastLine 
20

Paso 2 : establezcamos el número de líneas (al final de la secuencia) que pretendemos editar:

$ numberOfLines=7

$ echo $numberOfLines 
7

Paso 3 : calculemos la línea de inicio en función de variables anteriores, como las siguientes. Mira esto :

$ startLine=`expr $lastLine - $numberOfLines + 1`

$ echo $startLine 
14

Paso 4 : Ahora, podemos reemplazar las últimas 7 líneas de secuencia con algo más, como lo siguiente. Mira esto :

$ seq 20|sed -e "$startLine,+$numberOfLines{s/[12]/WoW/}"
1
2
3
4
5
6
7
8
9
10
11
12
13
WoW4
WoW5
WoW6
WoW7
WoW8
WoW9
WoW0

El paso 4 está utilizando la sección 4.4 de la página de manual de sed que dice:

'ADDR1,+N'
     Matches ADDR1 and the N lines following ADDR1.

Paso 4, también está usando comillas dobles como se menciona aquí .


Bueno, los 4 pasos son innecesarios si usamos la respuesta de Gohu de esta manera:

$ seq 20 |tac|sed -e '1,7{s/[12]/WoW/}'|tac
1
2
3
4
5
6
7
8
9
10
11
12
13
WoW4
WoW5
WoW6
WoW7
WoW8
WoW9
WoW0
usuario3405291
fuente
0

Uso taily tubería para sed:

tail -n 20 file | sed 's/,/;/g'

Esto funciona en el archivo de las últimas 20 líneas. Si desea que las canges se dirijan directamente al archivo, use:

tail -n 20 file | sed -i 's/,/;/g'

John Goofy
fuente