separador script manejo comando columnas campos cadenas cadena buscar bash awk sed

bash - script - Usar Awk o Sed para virar en una declaración al final de una línea específica



manejo de cadenas en shell script (3)

Dado que la utilidad de ed veteranos ya no recibe suficiente atención:

a=5.3827 ed -s poscar1.cif <<EOF g/^_cell_length_a/$/ s//& $a/ w EOF

ed realmente edita un archivo en su lugar , a diferencia de sed con su opción -i [1] .

sed tomó prestada muchas características de ed , por lo que hay una superposición significativa en la funcionalidad, pero también hay diferencias importantes, algunas de las cuales aparecen aquí.

  • -s suprime los mensajes de estado de ed .
  • poscar1.cif es el archivo de entrada para editar en su lugar.
  • <<EOF ... es el documento aquí que contiene los comandos para ed - ed requiere que sus comandos provengan de stdin y que cada comando esté en su propia línea.
  • g/^_cell_length_a/$/ ... es una expresión regular (básica) que coincide con todas las líneas que contienen exactamente _cell_length_a - la g garantiza que no se informa ningún error si no hay ninguna coincidencia.
    • Tenga en cuenta que el $ es / -capa para protegerlo de la interpretación por parte del shell dentro del documento aquí (no estrictamente necesario en este caso, pero sí buenas prácticas).
  • s//& $a/ ... // repite la búsqueda de la expresión regular utilizada más recientemente en una línea coincidente y reemplaza la coincidencia consigo misma ( & ), seguida de un espacio y el valor de la variable $a .
    • Tenga en cuenta que dado que el delimitador de apertura ( EOF ) del documento aquí no está citado , las expansiones de variable de shell SI tienen lugar; en esencia, los contenidos son tratados por el intérprete de comandos como el contenido de una cadena de comillas dobles.
  • w escribe el búfer modificado de nuevo en el archivo de entrada.
    • Para la depuración, use ,p en lugar de w para imprimir solo el búfer modificado, sin volver a escribirlo en el archivo.

[1] Actualización in situ:

Más precisamente, ed conserva el inodo existente del archivo, lo que garantiza que se conserven todos los atributos del archivo.
Sin embargo, no sobrescribe bytes individuales del archivo existente, sino que lee el archivo completo en un búfer en la memoria y escribe todo el búfer en el archivo cuando se le solicita.
Esto hace que ed sea adecuado solo para archivos lo suficientemente pequeños como para leerlos en la memoria como un todo .

Por el contrario, sed -i ( GNU y BSD sed ), su contraparte GNU 4.1+, awk -i inplace , y también perl -i reemplazan el archivo original por uno nuevo , lo que implica que:

  • destruir enlaces simbólicos (!) - si el archivo de entrada fue un enlace simbólico , se reemplaza con un archivo común del mismo nombre
    • Un escenario común en el que eso importa: digamos que el archivo de inicialización de shell ~/.bashrc es un enlace simbólico a un archivo en otro lugar que se mantiene bajo control de fuente; luego instala una herramienta que usa sed -i para modificar ~/.bashrc , lo que da como resultado que se sustituya por un archivo normal, y el enlace a su versión controlada por código fuente se rompe.
    • Además, el comportamiento de BSD sed incluso presenta un riesgo de seguridad (ver más abajo).
  • no conservar la fecha original de creación del archivo (cuando sea compatible, por ejemplo, en OSX)
  • lo hacen , sin embargo,

    • conservar los atributos extendidos (cuando sea compatible, por ejemplo, en OSX)
    • preservar los permisos de archivos

      • Precaución: BSD sed introduce un riesgo de seguridad con respecto a los enlaces simbólicos (el comportamiento aún está presente a partir de la versión que viene con FreeBSD 10):
        • Los permisos del enlace simbólico se copian en el archivo de reemplazo, no en el destino del enlace simbólico. Como los enlaces simbólicos obtienen permisos ejecutables de manera predeterminada, invariablemente se terminará con un archivo ejecutable , ya sea que el archivo de entrada sea ejecutable o no.
      • Afortunadamente, GNU sed maneja este escenario correctamente.

sed , gawk y perl podrían abordar los problemas anteriores mediante la adopción de medidas adicionales, pero hay una cosa que solo se puede garantizar si se retiene el inodo original, como lo hace ed :

Cuando un archivo está siendo monitoreado por cambios por su número de inodo (por ejemplo, con tail -f ), no preservar el inode rompe esa monitorización.

Tengo un archivo que poscar1.cif y me gustaría insertar el contenido de una variable en una línea específica de este archivo.

Por ejemplo, la línea 24 , que actualmente dice:

_cell_length_a

Me gustaría virar el contenido de mi variable a (definida en mi función como a=5.3827 ) de modo que la línea ahora lea:

_cell_length_a 5.3827

¿Hay alguna manera de hacer esto usando sed o awk? Estoy usando un script bash para lograr esto (el script completo es demasiado grande para publicarlo, desafortunadamente).


Puede usar sed para hacerlo, dependiendo de su respuesta a la pregunta de dawg como

sed -i -e ''24s/$/5.3827/'' poscar1.cif

o si es el patrón

sed -i -e ''/_cell_length_a/s/$/5.3827/'' poscar1.cif

El primero va a la línea con el número dado, el último se aplicará en cualquier línea que coincida con el patrón en el primer conjunto de barras diagonales. En cualquier caso, "reemplazará" el final de la línea con el valor entre las dos barras finales.


Usando tu ejemplo, podrías hacer algo como esto:

sed -i ''s//(_cell_length_a/)//1 5.3827/'' poscar1.cif

dónde,

  • la opción -i dice que se edite el archivo en su lugar, en lugar de crear una copia
  • la parte citada de aspecto funky es una cadena que especifica una expresión regular, también conocida como regex
  • poscar1.cif es el archivo

La sintaxis de expresiones regulares es difícil de leer. El formato básico para buscar y reemplazar es:

s/find/replace/

Donde find es el texto de la línea que está buscando y replace es el texto para reemplazar ese texto.

Si queremos usar parte de la cadena de búsqueda en nuestro reemplazo, la agrupamos rodeándola con /( y /) y luego usamos /1 para referirnos a ella en la cadena de reemplazo. Los siguientes anexos reemplazan a cualquier línea que consiste en find:

s//(find/)//1replace/

Tenga en cuenta que hay caracteres especiales de escape o metacaracteres que debe tratar especialmente si la cadena los contiene.