search - siguiente - ¿Cómo puedo buscar y reemplazar recursivamente en un directorio en Vim?
usar vi (6)
Aunque soy un usuario de Vim, generalmente uso find
y sed
para este tipo de cosas. La sintaxis de sed
regulares para sed
es similar a la de Vim (ambos son descendientes de ed
), aunque no idénticos. Con GNU sed, también puede usar -i
para ediciones in situ (normalmente, sed
emite la versión modificada a stdout).
Por ejemplo:
find project -name ''*.rb'' -type f -exec sed -i -e ''s/regex/replacement/g'' -- {} +
Pieza por pieza:
-
project
= buscar en el árbol "proyecto" -
-name ''*.rb''
= para las cosas cuyos nombres coinciden con ''* .rb'' -
-type f
= y son archivos regulares (no directorios, tuberías, enlaces simbólicos, etc.) -
-exec sed
= ejecutarsed
con estos argumentos:-
-i
= con ediciones en el lugar -
-e ''s/regex/replacement/g''
= ejecuta un comando "sustituto" (que es casi idéntico al de Vim:s
, pero nota falta de%
- es el valor predeterminado ensed
) -
--
= fin de las banderas, los nombres de archivo comienzan aquí -
{}
= esto indica que los nombres de archivos que encontró deben colocarse en la línea de comandos de sed aquí -
+
= Esto indica que la acción-exec
ha finalizado, y queremos agrupar los argumentos en la menor cantidad posible de invocacionessed
(generalmente más eficiente que ejecutarlo una vez por nombre de archivo). Para ejecutarlo una vez por nombre de archivo, puede usar/;
en lugar de+
.
-
Esta es la solución general con GNU sed
y find
. Esto se puede acortar un poco en casos especiales. Por ejemplo, si sabe que su patrón de nombre no coincidirá con ningún directorio, puede dejarlo fuera -type f
. Si sabe que ninguno de sus archivos comienza con un -
puede omitir --
. Aquí hay una respuesta que publiqué a otra pregunta con más detalles sobre cómo pasar los nombres de archivo encontrados con find
a otros comandos.
Descubrí el comando sustituto de Vim ...
:%s/replaceme/replacement/gi
Y vimgrep ...
:vimgrep /findme/gj project/**/*.rb
¿Hay alguna manera de combinarlos para reemplazar a todos los archivos en un directorio?
Esto funciona para una pequeña cantidad de archivos.
vim `encontrar. -type f `
: bufdo% s / patrón / reemplazo / gec | actualizar
Hay un complemento que se esfuerza por hacer justamente eso: Vimgrep Replace .
Oh, espera ... hay otros: Global Replace , EasyGrep .
Para una solución sin complementos, quizás argdo
ayudaría si pudieras obtener la salida de vimgrep
en la lista de argumentos (que se puede configurar con args
), pero no puedo entender los detalles. Estaría feliz si alguien tomara la idea y la mejorara ... así que aquí está.
La idea básica detrás del primer complemento (supongo que los otros también ...) es usar primero vimgrep
, luego recorrer las coincidencias con :cnext
y aplicar el comando de sustitución en cada línea. Una función para lograr esto podría ser lo suficientemente pequeña como para ponerlo en .vimrc. (¿Tal vez puede levantar uno de las fuentes de los complementos?)
(Supongo que hgimenez podría estar buscando una solución, pero si es apropiado o no, probablemente dependería de la cantidad de archivos que se procesarán ... Los complementos deberían estar bien, independientemente).
Puede ejecutar vimgrep y luego grabar una macro que va a cada línea en la salida de vimgrep y la reemplaza, algo como esto: (¡no escriba los # comentarios!)
:set autowrite #automatically save the file when we change buffers
:vimgrep /pattern/ ./**/files
qa #start recording macro in register a
:s/pattern/replace/g #replace on the current line
:cnext #go to next matching line
q #stop recording
10000@a #repeat the macro 10000 times, or until stopped by
#an "error" such as reaching the end of the list
:set noautowrite
No lo he probado, por lo que puede necesitar un pequeño ajuste: pruébelo en algunos archivos para que no le importe que lo arruinen primero.
La ventaja de este exceso de sed es que Vim Regex son más potentes, y puede agregar la opción c a: s para verificar cada reemplazo.
Editar : modifiqué mi publicación original porque estaba equivocada. Estaba usando: 1vimgrep para encontrar la primera coincidencia en cada archivo, pero leí mal los documentos, solo encuentra una coincidencia en todos los archivos.
Una forma sería abrir todos los archivos en los que desea ejecutar la sustitución (o cualquier comando) y ejecutar :bufdo <cmd>
, que ejecutará <cmd>
en todos los búferes abiertos.
args
y argdo
deberían hacer lo que necesites, por ejemplo
:args spec/javascripts/**/*.*
:argdo %s/foo/bar/g
Vea esta página .