Quiero buscar y reemplazar texto en un gran conjunto de archivos, excluyendo algunas instancias. Para cada línea, quiero un aviso que me pregunte si necesito reemplazar esa línea o no. Algo similar a los de vim :%s/from/to/gc
(con la c
solicitud de confirmación), pero en un conjunto de carpetas. ¿Hay alguna buena herramienta de línea de comandos o script que pueda usarse?
11
s/from/to/g
con un error de formato después, en lugar de hacers/from/to/gc
hincapié en loc
que había intentado escribir (no puede hacerlo con Markdown, puede hacerlo con<code>
y<strong>
etiquetas HTML).Respuestas:
¿Por qué no usar vim?
Abra todos los archivos en vim
O abra solo archivos relevantes (como lo sugiere Caleb)
Y luego ejecute el reemplazo en todos los búferes
También puedes hacerlo
sed
, pero mi conocimiento de sed es limitado.fuente
grep
lugar defind
abrir solo archivos que tengan coincidencias conocidas.vim $(grep 'from' . -Rl)
Puede hacer algo crudo con un pequeño script de Perl que recibe instrucciones de realizar reemplazos línea por línea (
-l -pe
) en los archivos pasados como argumentos (-i
):Las posibles mejoras serían colorear partes de la solicitud y apoyar cosas como "reemplazar todas las ocurrencias en el archivo actual". Solicitar por separado cada aparición en una línea sería más difícil.
Segunda parte, haciendo coincidir los archivos. Si no hay demasiados archivos involucrados y está ejecutando zsh, puede hacer coincidir todos los archivos en el directorio actual y sus subdirectorios de forma recursiva:
Si su shell es bash ≥4, puede ejecutar
perl … **/*
, pero eso producirá mensajes de error espurios porque sed intentará (y fallará) ejecutar en directorios. Si solo desea realizar el reemplazo en un conjunto de archivos como archivos C, puede restringir las coincidencias (que funciona en bash ≥4 o zsh):Si necesita un control más preciso sobre qué archivos está reemplazando, o su shell no tiene la construcción de coincidencia de directorio recursiva
**
, o si tiene demasiados archivos y obtiene un error de "línea de comando demasiado larga", usefind
. Por ejemplo, para realizar un reemplazo en todos los archivos nombrados*.h
o*.c
en el directorio actual y sus subdirectorios (en sistemas más antiguos, es posible que deba usar en\;
lugar de+
al final de la línea (el+
formulario es más rápido pero no está disponible en todas partes).Dicho esto, me quedaría con un editor interactivo si necesita interacción. Gert ha mostrado una forma de hacerlo en Vim , aunque requiere abrir todos los archivos que desea buscar, lo que puede ser un problema si hay muchos.
En Emacs, así es como puedes hacer esto:
M-x find-name-dired
(especifique un directorio de nivel superior) oM-x find-dired
(especifique unafind
línea de comando arbitraria ).t
para marcar todos los archivos, luegoQ
(dired-do-query-replace-regexp
) para realizar un reemplazo con una solicitud en los archivos marcados.fuente
sdiff
(ver http://www.gnu.org/software/diffutils/manual/diffutils.html#Invoking-sdiff ) podría ser útil aquí. Con él puedes hacer parches interactivos. Entonces, hacerlo con un archivo temporal que creó al realizar operaciones de reemplazosed
podría ser una posible solución:(Bucle de archivos que utiliza la sustitución de procesos que no son POSIX y
read -d
según lo respaldado, por ejemplo, porbash
).fuente