La búsqueda de Vim reemplaza todos los archivos en la carpeta actual (proyecto)

37

Una de las preguntas abiertas que tengo sobre Vim es si hay una manera de realizar una búsqueda / reemplazo en el proyecto actual (tenga en cuenta si uso esta noción heredada de otros editores).

Por ejemplo, supongamos que quiero buscar en mis archivos de proyecto el nombre de un método y cambiar el nombre de todas las instancias de esa llamada al método.

Así es como puedo proceder con Sublime.

ingrese la descripción de la imagen aquí

¿Cómo haría esto en Vim (posiblemente MacVim) sin depender de otros programas como acko sed?

Simone Carletti
fuente

Respuestas:

35

Hay varias formas de hacerlo.

Directorio actual interno

Si desea realizar la búsqueda / reemplazo en un árbol de proyecto, puede usar la lista de argumentos de Vim .

Simplemente abra Vim y luego use el :argscomando para completar la lista de argumentos. Puede pasar varios nombres de archivo o incluso globos.

Por ejemplo, :args **/*.rbbuscará de forma recursiva el directorio actual en busca de archivos ruby. Tenga en cuenta que esto también es como abrir Vim con vim **/*.rb. Incluso puede usar el findcomando del shell para obtener una lista de todos los archivos en el directorio actual ejecutando:

:args `find . -type f`

Puede ver la lista de argumentos actuales ejecutándose :argssolo. Si desea agregar o eliminar archivos de la lista, puede usar :argaddlos :argdeletecomandos o respectivamente.

Una vez que esté satisfecho con la lista, ahora puede usar el poderoso :argdocomando de Vim que ejecuta un comando para cada archivo en la lista de argumentos::argdo %s/search/replace/g

Aquí hay algunos consejos para buscar (basados ​​en algunos de los comentarios):

  1. Use un límite de palabra si desea buscar "foo" pero no "foo_bar". Use las construcciones \<y \>alrededor del patrón de búsqueda de la siguiente manera::argdo %s/\<search\>/foobar/g
  2. Use una /cmarca de búsqueda si desea que Vim solicite confirmación antes de reemplazar un término de búsqueda.
  3. Use una /emarca de búsqueda si desea omitir los errores de "patrón no encontrado".
  4. También puede optar por guardar el archivo después de realizar la búsqueda: :argdo %s/search/replace/g | update. Aquí, :updatese usa porque solo guardará el archivo si ha cambiado.

Tampones abiertos

Si ya tiene búferes abiertos en los que desea realizar la búsqueda / reemplazo, puede usar :bufdo, que ejecuta un comando para cada archivo en su lista de búferes ( :ls).

El comando es muy similar a :argdo: :bufdo %s/search/replace/g

Similar a :argdoy :bufdo, hay :windoy :tabdoque actúan en ventanas y pestañas respectivamente. Se usan con menos frecuencia pero aún son útiles para saber.

akshay
fuente
44
Probablemente sea una buena idea usar la /cbandera para confirmar las sustituciones.
romainl
3
También recomendaría usar límites de palabras \<y \>alrededor searchpara evitar reemplazos parciales de palabras.
tommcdo
1
Otro comentario es que el directorio de trabajo de vim es, por defecto, donde inició vim, no el directorio del archivo actual. Puede configurar el directorio de trabajo para el archivo actual usando :cd %:p:h. Otras opciones de directorio de trabajo se enumeran en vim.wikia.com/wiki/Set_working_directory_to_the_current_file .
studgeek
30

Digamos que tenemos una estructura de proyecto simple como esta:

ingrese la descripción de la imagen aquí

greeting.txt se parece a

ingrese la descripción de la imagen aquí

e info / age.txt parece

ingrese la descripción de la imagen aquí

Digamos que queremos reemplazar todas las ocurrencias de Sam con Bob. Esto es lo que haríamos:

  1. Establecer directorio de trabajo

    Asegúrese de que el directorio de trabajo actual de Vim sea la raíz del proyecto (no le mostrará cómo hacerlo aquí).

  2. Buscar archivos que contienen 'Sam'

    Use el comando vimgrep de Vim para buscar todas las ocurrencias de Sam dentro del proyecto (nota: las **/*búsquedas en todos los archivos de forma recursiva)

    :vimgrep /Sam/gj **/*
    

    Esto llenará la lista de soluciones rápidas con todas las instancias de Sam. Si desea ver la lista de soluciones rápidas, puede usar el comando Vim:copen ingrese la descripción de la imagen aquí

  3. Sustituir dentro de todos los archivos que contienen 'Sam'

    Ahora queremos ejecutar el comando sustituto de Vim dentro de cada archivo en la lista de soluciones rápidas. Podemos hacer esto usando el :cfdo {cmd}comando que ejecuta {cmd} en cada archivo en la lista de soluciones rápidas. El {cmd} específico que queremos usar es substituteo spara abreviar. La línea completa se vería así:

    :cfdo %s/Sam/Bob/g
    

    Puede agregar la bandera c para confirmar todos los reemplazos si lo desea:

    :cfdo %s/Sam/Bob/gc
    
  4. Guardar todos los archivos

    :cfdo update
    
Niko Bellic
fuente
2
Me gusta mas esto. Es simple y funciona con Ack (o cualquier complemento que llene la ventana QuickFix).
Zuhaib
1
Esta es una gran respuesta
Peoplee
2
Era conseguir "no escribir desde el último cambio", haciendo cfdo %s/Sam/Bob/g | updatefijo que para mí
hakunin
@hakunin Recomiendo configurar la hiddenopción :set hiddensi aún no lo ha hecho.
Niko Bellic
3

Aunque no es una solución VIM, si está utilizando VI / VIM puede que le resulte más fácil usar una solución CLI. Para cambiar todos los archivos en el directorio actual, use perlcomo se hizo para situaciones como esta:

$ perl -pi -e 's/foo/bar/g' *

Si necesita hacerlo también en subdirectorios, generalmente emparejo perlcon find:

$ find . -name '*' -print0 | xargs -0 perl -pi -e 's/foo/bar/g'

Lo bueno de esto es que puede refinar fácilmente la lista a tipos de archivos específicos. Por ejemplo, para restringir a archivos python:

$ perl -pi -e 's/foo/bar/g' *.py
$ find . -name '*.py' -print0 | xargs -0 perl -pi -e 's/foo/bar/g'
dotancohen
fuente
1

Para reemplazar la frase con otra, puede usar el modo Vim Ex.

Por ejemplo ( exes alias para vim -E):

$ ex -s +'bufdo!%s/foo/bar/g' -cxa *.*

Recursivamente en bash / zsh (con globstarset, por ejemplo shopt -s globstar):

$ ex -s +'bufdo!%s/foo/bar/g' -cxa **/*.*
$ ex -s +'n **/*.*' +'bufdo!%s/foo/bar/g' -cxa

Recursivamente (usando finde ignorando archivos ocultos como .gitarchivos):

$ find . -type f -not -path '*/\.*' -exec ex -s +'bufdo!%s/foo/bar/g' -cxa {} "+"

Nota: El :bufdocomando no es POSIX .

Nota: La sintaxis -not -path '*/\.*'se usa para ignorar los archivos ocultos (como .git).

kenorb
fuente
note que bufdo no es POSIX pubs.opengroup.org/onlinepubs/9699919799/utilities/ex.html
Steven Penny
0

Aquí está el comando de shell usando findy exeditor (sin usar:bufdo ):

find . -name '*.rb' -exec ex +'%s/foo/bar/ge' -V1 -scwq! {} ';'

Esto editará en el lugar todos los *.rbarchivos en la carpeta actual (recursivamente) y los reemplazará foocon bar.

kenorb
fuente