Inserte una línea en un número de línea específico con sed o awk

146

Tengo un archivo de script que necesito modificar con otro script para insertar un texto en la octava línea.

Cadena para insertar:, Project_Name=sowstesten un archivo llamado start.

Traté de usar awk y sed, pero mi comando se está confundiendo.

ashok
fuente

Respuestas:

231
sed -i '8i8 This is Line 8' FILE

insertos en la línea 8

8 This is Line 8

en el archivo ARCHIVO

-i realiza la modificación directamente al archivo ARCHIVO, sin salida a stdout, como se menciona en los comentarios de Glenn Jackman.

usuario desconocido
fuente
3
Sí, el modificador -i es específico para GNU-sed.
usuario desconocido
1
No. -i significa "modificar el archivo especificado en su lugar". Insertar vs. anexar se logra con '8isomething' vs. '8asomething', independiente del interruptor -i.
usuario desconocido el
11
usuarios de mac: con homebrew, brew install gnu-sedy luego usen esto congsed
cwd
44
¡Esto es súper útil! ¿Hay alguna forma de insertar espacios al principio de la línea? Noté SED no está prestando atención a los espacios en blanco inicial ...
elju
9
@elju: Sí, enmascararlo con una barra invertida: sed '8i\ 8 This is Line 8' FILE.
usuario desconocido
32

Una edrespuesta

ed file << END
8i
Project_Name=sowstest
.
w
q
END

.en su propia línea termina el modo de entrada; wescribe qen paz. GNU ed tiene un wqcomando para guardar y salir, pero los ed viejos no.

Lectura adicional: https://gnu.org/software/ed/manual/ed_manual.html

Glenn Jackman
fuente
19

OS X / macOS / FreeBSD sed

La -ibandera funciona de manera diferente en macOS sedque en GNU sed.

Aquí está la forma de usarlo en macOS / OS X:

sed -i '' '8i\
8 This is Line 8' FILE

Ver man 1 sedpara más información.

Mateusz Piotrowski
fuente
18

la respuesta awk

awk -v n=8 -v s="Project_Name=sowstest" 'NR == n {print s} {print}' file > file.new
Glenn Jackman
fuente
@glenn jackman Necesito ingresar #define SERVER@"http://10.35.42.54/ms0.8"a una línea en particular. ¿Cómo puedo conseguir esto?
Nevin Raj Victor
1
Creo que Nevin solo necesita escapar de las comillas en su cadena con barras invertidas
Chris Koknat
@waLLe, comience con la página de información de awk que tiene una buena descripción de cómo funciona awk. Aquí, tengo 2 pares "condición {acción}", el segundo no tiene condición, lo que significa que la acción se realiza para cada registro. Después de que termine de leer y aún tenga preguntas, avíseme.
Glenn Jackman
@glennjackman casi allí ... simplemente no entendí esto: archivo> archivo.nuevo
w411 3 de
"archivo" representa el nombre del archivo en el que está trabajando awk. >es el símbolo de redirección de shell para que la salida de awk se almacene en el archivo llamado "file.new".
Glenn Jackman
16

POSIX sed(y, por ejemplo, OS X sed, los sedsiguientes) ideben ir seguidos de una barra diagonal inversa y una nueva línea. Además, al menos OS X sedno incluye una nueva línea después del texto insertado:

$ seq 3|gsed '2i1.5'
1
1.5
2
3
$ seq 3|sed '2i1.5'
sed: 1: "2i1.5": command i expects \ followed by text
$ seq 3|sed $'2i\\\n1.5'
1
1.52
3
$ seq 3|sed $'2i\\\n1.5\n'
1
1.5
2
3

Para reemplazar una línea, puede usar los comandos c(cambiar) o s(sustituir) con una dirección numérica:

$ seq 3|sed $'2c\\\n1.5\n'
1
1.5
3
$ seq 3|gsed '2c1.5'
1
1.5
3
$ seq 3|sed '2s/.*/1.5/'
1
1.5
3

Alternativas usando awk:

$ seq 3|awk 'NR==2{print 1.5}1'
1
1.5
2
3
$ seq 3|awk '{print NR==2?1.5:$0}'
1
1.5
3

awkinterpreta las barras diagonales inversas en las variables pasadas con, -vpero no en las variables pasadas usando ENVIRON:

$ seq 3|awk -v v='a\ba' '{print NR==2?v:$0}'
1
a
3
$ seq 3|v='a\ba' awk '{print NR==2?ENVIRON["v"]:$0}'
1
a\ba
3

Ambos ENVIRONy -vestán definidos por POSIX.

Lri
fuente
7

Soluciones Perl:

rápido y sucio:

perl -lpe 'print "Project_Name=sowstest" if $. == 8' file

  • -l elimina las nuevas líneas y las agrega nuevamente, eliminando la necesidad de "\ n"
  • -p recorre el archivo de entrada, imprimiendo cada línea
  • -e ejecuta el código entre comillas simples

$. es el número de línea

equivalente a la solución awk de @ glenn, utilizando argumentos con nombre:

perl -slpe 'print $s if $. == $n' -- -n=8 -s="Project_Name=sowstest" file

  • -s permite un analizador de argumentos rudimentario
  • -- evita que -n y -s sean analizados por el analizador de argumentos perl estándar

argumentos de comando posicional:

perl -lpe 'BEGIN{$n=shift; $s=shift}; print $s if $. == $n' 8 "Project_Name=sowstest" file

Variables de entorno:

setenv n 8 ; setenv s "Project_Name=sowstest"
echo $n ; echo $s
perl -slpe 'print $ENV{s} if $. == $ENV{n}' file

ENV es el hash que contiene todas las variables de entorno

Getopt para analizar argumentos en hash% o:

perl -MGetopt::Std -lpe 'BEGIN{getopt("ns",\%o)}; print $o{s} if $. == $o{n}' -- -n 8 -s "Project_Name=sowstest" file

Getopt :: Nombres de opciones largos y más largos

perl -MGetopt::Long -lpe 'BEGIN{GetOptions(\%o,"line=i","string=s")}; print $o{string} if $. == $o{line}' -- --line 8 --string "Project_Name=sowstest" file

Getopt es la solución de biblioteca estándar recomendada.
Esto puede ser excesivo para los scripts de Perl de una línea, pero se puede hacer

Chris Koknat
fuente
2
Felicitaciones a Chris por tomarse el tiempo para explicar todo eso y exponerlo tan bien, pero wow, esta es la razón por la que no me gusta Perl.
rsaw
5

Para aquellos que están en SunOS que no es GNU, el siguiente código ayudará:

sed '1i\^J
line to add' test.dat > tmp.dat
  • ^ J se inserta con ^ V + ^ J
  • Agregue la nueva línea después de '1i.
  • \ DEBE ser el último carácter de la línea.
  • La segunda parte del comando debe estar en una segunda línea.
Nasri Najib
fuente
5

sed -e '8iProject_Name=sowstest' -i start usando GNU sed

Ejecución de muestra:

[root@node23 ~]# for ((i=1; i<=10; i++)); do echo "Line #$i"; done > a_file
[root@node23 ~]# cat a_file
Line #1
Line #2
Line #3
Line #4
Line #5
Line #6
Line #7
Line #8
Line #9
Line #10
[root@node23 ~]# sed -e '3ixxx inserted line xxx' -i a_file 
[root@node23 ~]# cat -An a_file 
     1  Line #1$
     2  Line #2$
     3  xxx inserted line xxx$
     4  Line #3$
     5  Line #4$
     6  Line #5$
     7  Line #6$
     8  Line #7$
     9  Line #8$
    10  Line #9$
    11  Line #10$
[root@node23 ~]# 
[root@node23 ~]# sed -e '5ixxx (inserted) "line" xxx' -i a_file
[root@node23 ~]# cat -n a_file 
     1  Line #1
     2  Line #2
     3  xxx inserted line xxx
     4  Line #3
     5  xxx (inserted) "line" xxx
     6  Line #4
     7  Line #5
     8  Line #6
     9  Line #7
    10  Line #8
    11  Line #9
    12  Line #10
[root@node23 ~]# 
jno
fuente
¿De dónde viene el final $de la línea 3 después de la inserción?
jww
Es de -Abandera a cat:)
jno
¿Qué pasa si la cadena que desea insertar contiene comillas, paréntesis, etc.?
Anentropic
Ver actualización del texto anterior. Eso significa que tendrá que escapar de esos caracteres según corresponda.
junio
0

sed -i "" -e $ '4 a \\ n''Project_Name = sowstest' start

  • Esta línea funciona bien en macOS
Elza James
fuente