GNU/Linux >> Tutoriales Linux >  >> Linux

¿Cómo se reemplaza el texto similar a sed con python?

Puedes hacerlo así:

with open("/etc/apt/sources.list", "r") as sources:
    lines = sources.readlines()
with open("/etc/apt/sources.list", "w") as sources:
    for line in lines:
        sources.write(re.sub(r'^# deb', 'deb', line))

La declaración with garantiza que el archivo se cierre correctamente y vuelva a abrir el archivo en "w" mode vacía el archivo antes de escribir en él. re.sub(patrón, reemplazar, cadena) es el equivalente de s/patrón/reemplazar/ en sed/perl.

Editar: sintaxis fija en el ejemplo


Creación de un sed de cosecha propia reemplazo en Python puro con no comandos externos o dependencias adicionales es una noble tarea cargada de nobles minas terrestres. ¿Quién lo hubiera pensado?

Sin embargo, es factible. También es deseable. Todos hemos estado allí, gente:"Necesito munge algunos archivos de texto sin formato, pero solo tengo Python, dos cordones de plástico y una lata mohosa de cerezas marrasquino de grado búnker. Ayuda".

En esta respuesta, ofrecemos la mejor solución que combina la genialidad de las respuestas anteriores sin todo ese desagradable no. -genialidad. Como señala plundra, la respuesta de primera categoría de David Miller escribe el archivo deseado de forma no atómica y, por lo tanto, invita a condiciones de carrera (por ejemplo, de otros subprocesos y/o procesos que intentan leer ese archivo simultáneamente). Eso es malo. La excelente respuesta de Plundra resuelve eso problema mientras presenta aún más, incluidos numerosos errores de codificación fatales, una vulnerabilidad de seguridad crítica (no se pueden conservar los permisos y otros metadatos del archivo original) y la optimización prematura que reemplaza las expresiones regulares con la indexación de caracteres de bajo nivel. Eso también es malo.

¡Impresionante, uníos!

import re, shutil, tempfile

def sed_inplace(filename, pattern, repl):
    '''
    Perform the pure-Python equivalent of in-place `sed` substitution: e.g.,
    `sed -i -e 's/'${pattern}'/'${repl}' "${filename}"`.
    '''
    # For efficiency, precompile the passed regular expression.
    pattern_compiled = re.compile(pattern)

    # For portability, NamedTemporaryFile() defaults to mode "w+b" (i.e., binary
    # writing with updating). This is usually a good thing. In this case,
    # however, binary writing imposes non-trivial encoding constraints trivially
    # resolved by switching to text writing. Let's do that.
    with tempfile.NamedTemporaryFile(mode='w', delete=False) as tmp_file:
        with open(filename) as src_file:
            for line in src_file:
                tmp_file.write(pattern_compiled.sub(repl, line))

    # Overwrite the original file with the munged temporary file in a
    # manner preserving file attributes (e.g., permissions).
    shutil.copystat(filename, tmp_file.name)
    shutil.move(tmp_file.name, filename)

# Do it for Johnny.
sed_inplace('/etc/apt/sources.list', r'^\# deb', 'deb')

massedit.py (http://github.com/elmotec/massedit) hace el andamiaje por usted dejando solo la expresión regular para escribir. Todavía está en versión beta, pero estamos buscando comentarios.

python -m massedit -e "re.sub(r'^# deb', 'deb', line)" /etc/apt/sources.list

mostrará las diferencias (antes/después) en formato diff.

Agregue la opción -w para escribir los cambios en el archivo original:

python -m massedit -e "re.sub(r'^# deb', 'deb', line)" -w /etc/apt/sources.list

Alternativamente, ahora puede usar la API:

>>> import massedit
>>> filenames = ['/etc/apt/sources.list']
>>> massedit.edit_files(filenames, ["re.sub(r'^# deb', 'deb', line)"], dry_run=True)

Este es un enfoque tan diferente que no quiero editar mi otra respuesta. with anidado ya que no uso 3.1 (Donde with A() as a, B() as b: funciona).

Puede ser un poco exagerado cambiar la lista de fuentes, pero quiero publicarla para futuras búsquedas.

#!/usr/bin/env python
from shutil   import move
from tempfile import NamedTemporaryFile

with NamedTemporaryFile(delete=False) as tmp_sources:
    with open("sources.list") as sources_file:
        for line in sources_file:
            if line.startswith("# deb"):
                tmp_sources.write(line[2:])
            else:
                tmp_sources.write(line)

move(tmp_sources.name, sources_file.name)

Esto debería garantizar que no haya condiciones de carrera para que otras personas lean el archivo. Ah, y prefiero str.startswith(...) cuando se puede prescindir de una expresión regular.


Linux
  1. Manipulación de texto en la línea de comando con sed

  2. ¿Cómo insertar texto antes de la primera línea de un archivo?

  3. ¿Cómo reemplazar una cadena con una cadena que contiene una barra oblicua con Sed?

  4. ¿Cómo usar Sed o Ex para reemplazar un bloque (código de varias líneas) con un nuevo bloque de texto (código)?

  5. ¿Cómo analizar cada línea de un archivo de texto como un argumento para un comando?

Manipulación de texto con sed y grep

¿Cómo usar sed para reemplazar la variable de un archivo de configuración?

reemplazar la enésima ocurrencia de cadena en cada línea de un archivo de texto

¿Cómo reemplazar un archivo en jar con línea de comando en Linux?

sed:¿cómo reemplazar la línea si se encuentra o agregar al final del archivo si no se encuentra?

¿Cómo reemplazar recursivamente los caracteres con sed?