Su problema con Vim es que no entiendes vi .
Usted menciona el corte con yy
y se quejan de que casi nunca quieren cortar líneas enteras. De hecho, los programadores que editan el código fuente, muy a menudo quieren trabajar en líneas enteras, rangos de líneas y bloques de código. Sin embargo, yy
es sólo una de las muchas formas de introducir texto en el buffer de copia anónima (o "registro", como se llama en vi ).
El "zen" de vi es que estás hablando un idioma. El principio y
es un verbo. El enunciado yy
es un sinónimo de y_
. El y
se duplica para que sea más fácil de escribir, ya que es una operación muy común.
Esto también puede expresarse como dd
P
(borrar la línea actual y pegar una copia en su lugar; dejando una copia en el registro anónimo como efecto secundario). La página web y
y d
Los "verbos" toman como "sujeto" cualquier movimiento. Así, yW
es "tirar desde aquí (el cursor) hasta el final de la palabra actual/siguiente (grande)" y y'a
es "tirar desde aquí hasta la línea que contiene la marca llamada ' a '."
Si sólo entiendes los movimientos básicos del cursor hacia arriba, abajo, izquierda y derecha, entonces vi no será más productivo que una copia del "bloc de notas" para ti. (De acuerdo, seguirás teniendo resaltado de sintaxis y la capacidad de manejar archivos más grandes que unos insignificantes ~45KB; pero trabaja conmigo aquí).
vi tiene 26 "marcas" y 26 "registros". Una marca se establece en cualquier posición del cursor utilizando la tecla m
de mando. Cada marca se designa con una sola letra minúscula. Así, ma
establece el valor de ' a a la ubicación actual, y mz
establece el valor de ' z ' marca. Puede desplazarse a la línea que contiene una marca utilizando la tecla '
(comillas simples). Así, 'a
se desplaza al principio de la línea que contiene el a ' marca. Puede desplazarse a la ubicación precisa de cualquier marca utilizando el botón `
(backquote). Así, `z
se desplazará directamente al lugar exacto de la sección ' z ' marca.
Como se trata de "movimientos", también pueden utilizarse como temas para otros "enunciados".
Así, una forma de cortar una selección arbitraria de texto sería soltar una marca (yo suelo usar ' a ' como mi "primera" marca, ' z ' como mi siguiente marca, ' b ' como otro, y ' e ' como otra más (no recuerdo haber utilizado nunca de forma interactiva más de cuatro marcas en 15 años de uso de vi (uno crea sus propias convenciones sobre cómo las marcas y los registros son utilizados por las macros que no perturban el contexto interactivo). Luego vamos al otro extremo de nuestro texto deseado; podemos empezar por cualquiera de los dos extremos, no importa. Entonces podemos usar simplemente d`a
para cortar o y`a
para copiar. Así, todo el proceso tiene una sobrecarga de 5 pulsaciones (seis si empezamos en modo "insertar" y necesitamos Esc modo de comando de salida). Una vez que hemos cortado o copiado, pegar una copia es una sola pulsación: p
.
Digo que esta es una forma de cortar o copiar texto. Sin embargo, es sólo una de las muchas. A menudo podemos describir más sucintamente el rango de texto sin tener que mover el cursor y soltar una marca. Por ejemplo, si estoy en un párrafo de texto puedo usar {
y }
movimientos al principio o al final del párrafo, respectivamente. Así, para mover un párrafo de texto lo corto usando {
d}
(3 pulsaciones). (Si resulta que ya estoy en la primera o última línea del párrafo, puedo utilizar simplemente d}
o d{
respectivamente.
La noción de "párrafo" se inclina por algo que suele ser intuitivamente razonable. Por ello, suele funcionar tanto para el código como para la prosa.
Con frecuencia conocemos algún patrón (expresión regular) que marca un extremo u otro del texto en el que estamos interesados. Buscar hacia delante o hacia atrás son movimientos en vi . Por lo tanto, también pueden utilizarse como "sujetos" en nuestras "declaraciones". Así que puedo usar d/foo
para cortar desde la línea actual hasta la siguiente línea que contiene la cadena "foo" y y?bar
para copiar de la línea actual a la línea más reciente (anterior) que contenga "bar". Si no quiero líneas enteras puedo seguir utilizando los movimientos de búsqueda (como declaraciones propias), soltar mi(s) marca(s) y utilizar el `x
como se ha descrito anteriormente.
Además de los "verbos" y los "sujetos" vi también tiene "objetos" (en el sentido gramatical del término). Hasta ahora sólo he descrito el uso del registro anónimo. Sin embargo, puedo utilizar cualquiera de los 26 registros "con nombre" mediante prefijando la referencia "objeto" con "
(el modificador de comillas dobles). Así, si utilizo "add
Estoy cortando la línea actual en el ' a y si utilizo "by/foo
entonces estoy tirando una copia del texto de aquí a la siguiente línea que contiene "foo" en el ' b ' registro. Para pegar desde un registro simplemente antepongo el pegado con la misma secuencia de modificadores: "ap
pega una copia del archivo ' a en el texto después del cursor y "bP
pega una copia de ' b ' antes de la línea actual.
Esta noción de "prefijos" también añade los análogos de los "adjetivos" y "adverbios" gramaticales a nuestro "lenguaje" de manipulación de textos. La mayoría de las órdenes (verbos) y movimientos (verbos u objetos, según el contexto) también pueden llevar prefijos numéricos. Así, 3J
significa "unir las tres líneas siguientes" y d5}
significa "borrar desde la línea actual hasta el final del quinto párrafo a partir de aquí".
Todo esto es de nivel intermedio vi . Nada de esto es Vim específicos y hay trucos mucho más avanzados en vi si estás preparado para aprenderlas. Si sólo dominas estos conceptos intermedios, probablemente descubrirás que rara vez necesitas escribir macros porque el lenguaje de manipulación de texto es lo suficientemente conciso y expresivo como para hacer la mayoría de las cosas fácilmente usando el lenguaje "nativo" del editor.
Una muestra de trucos más avanzados:
Hay una serie de :
comandos, sobre todo el :% s/foo/bar/g
técnica de sustitución global. (Esto no es avanzado, pero otros :
puede ser). El conjunto :
conjunto de comandos fue históricamente heredado por vi de las encarnaciones anteriores de la ed (editor de líneas) y posteriormente el ex (editor de líneas extendido). De hecho vi se llama así porque es la interfaz visual de ex .
:
Los comandos normalmente operan sobre líneas de texto. ed y ex se escribieron en una época en la que las pantallas de los terminales eran poco comunes y muchos de ellos eran dispositivos de "teletipo" (TTY). Así que era habitual trabajar a partir de copias impresas del texto, utilizando comandos a través de una interfaz extremadamente escueta (las velocidades de conexión habituales eran de 110 baudios, o, aproximadamente, 11 caracteres por segundo, lo que es más lento que un mecanógrafo rápido; los retrasos eran habituales en las sesiones interactivas multiusuario; además, a menudo había cierta motivación para conservar el papel).
Así que la sintaxis de la mayoría de los :
incluye una dirección o rango de direcciones (número de línea) seguido de un comando. Naturalmente, se pueden utilizar números de línea literales: :127,215 s/foo/bar
para cambiar la primera aparición de "foo" por "bar" en cada línea entre 127 y 215. También se podrían utilizar algunas abreviaturas como .
o $
para la línea actual y la última, respectivamente. También se pueden utilizar prefijos relativos +
y -
para referirse a los desplazamientos posteriores o anteriores a la línea actual, respectivamente. Así: :.,$j
que significa "desde la línea actual hasta la última línea, unirlas todas en una sola línea". :%
es sinónimo de :1,$
(todas las líneas).
El :... g
y :... v
Los comandos merecen alguna explicación, ya que son increíblemente poderosos. :... g
es un prefijo para aplicar "globalmente" un comando posterior a todas las líneas que coincidan con un patrón (expresión regular) mientras que :... v
aplica dicho comando a todas las líneas que NO coinciden con el patrón dado ("v" de "conVerse"). Al igual que con otros ex Estos comandos pueden ir precedidos de referencias de direcciones/rangos. Así, :.,+21g/foo/d
significa "borrar cualquier línea que contenga la cadena "foo" desde la actual hasta las siguientes 21 líneas" mientras que :.,$v/bar/d
significa "desde aquí hasta el final del archivo, borra todas las líneas que NO contengan la cadena "bar".
Es interesante que el comando común de Unix grep en realidad se inspiró en esto ex (y se llama así por la forma en que se documentó). El ex comando :g/re/p
(grep) era la forma en que se documentaba cómo "imprimir" globalmente las líneas que contenían una "expresión regular" (re). Cuando ed y ex fueron utilizados, el :p
fue uno de los primeros que se aprendió y a menudo el primero que se utiliza al editar cualquier archivo. Era la forma de imprimir el contenido actual (normalmente sólo una página completa a la vez usando :.,+25p
o algo así).
Tenga en cuenta que :% g/.../d
o (su contraparte reVerse/conVerse: :% v/.../d
son los patrones de uso más comunes. Sin embargo, hay un par de otros ex
comandos que vale la pena recordar:
Podemos utilizar m
para mover las líneas, y j
para unir líneas. Por ejemplo, si tienes una lista y quieres separar todas las cosas que coinciden (o a la inversa, que NO coinciden con algún patrón) sin borrarlas, entonces puedes usar algo como :% g/foo/m$
... y todas las líneas "foo" se habrán movido al final del archivo. (Tenga en cuenta el otro consejo sobre el uso del final de su archivo como espacio de borrado). Esto habrá preservado el orden relativo de todas las líneas "foo", al tiempo que las habrá extraído del resto de la lista. (Esto equivaldría a hacer algo como: 1G!GGmap!Ggrep foo<ENTER>1G:1,'a g/foo'/d
(copiar el archivo a su propia cola, filtrar la cola a través de grep
y borrar todo el material de la cabeza).
Para unir líneas normalmente puedo encontrar un patrón para todas las líneas que necesitan ser unidas a su predecesor (todas las líneas que comienzan con "^ " en lugar de "^ * " en alguna lista de viñetas, por ejemplo). Para ese caso utilizaría :% g/^ /-1j
(por cada línea coincidente, sube una línea y únelas). (BTW: para las listas de viñetas, intentar buscar las líneas de viñetas y unirlas a la siguiente no funciona por un par de razones... puede unir una línea de viñetas a otra, y no unirá ninguna línea de viñetas a todo de sus continuaciones; sólo funcionará por pares en las coincidencias).
Casi no hace falta mencionar que puedes usar nuestro viejo amigo s
(sustituir) con el g
y v
(global/converso-global). Normalmente no es necesario hacerlo. Sin embargo, considere algún caso en el que quiera realizar una sustitución sólo en las líneas que coincidan con algún otro patrón. A menudo puede utilizar un patrón complicado con capturas y utilizar referencias inversas para preservar las partes de las líneas que NO quiere cambiar. Sin embargo, a menudo será más fácil separar la coincidencia de la sustitución: :% g/foo/s/bar/zzz/g
-- para cada línea que contenga "foo" sustituya todos los "bar" por "zzz". (Algo así como :% s/\(.*foo.*\)bar\(.*\)/\1zzz\2/g
sólo funcionaría para los casos en los que "bar" fuera PRECEDIDO por "foo" en la misma línea; ya es bastante complicado, y tendría que modificarse aún más para captar todos los casos en los que "bar" precediera a "foo")
La cuestión es que hay más que p
, s
y d
líneas en el ex
conjunto de comandos.
El :
Las direcciones también pueden referirse a las marcas. Así, se puede utilizar: :'a,'bg/foo/j
para unir cualquier línea que contenga la cadena foo con su línea subsiguiente, si se encuentra entre las líneas entre el ' a ' y ' b ' marcas. (Sí, todo lo anterior ex
Los ejemplos de comandos pueden limitarse a subconjuntos de líneas del archivo anteponiendo este tipo de expresiones de direccionamiento).
Eso es bastante oscuro (sólo he utilizado algo así unas pocas veces en los últimos 15 años). Sin embargo, admito que a menudo he hecho cosas de forma iterativa e interactiva que probablemente podrían haberse hecho de forma más eficiente si me hubiera tomado el tiempo de pensar en el encantamiento correcto.
Otro muy útil vi o ex comando es :r
para leer el contenido de otro archivo. Así: :r foo
inserta el contenido del archivo llamado "foo" en la línea actual.
Más potente es el :r!
de mando. Esto lee los resultados de un comando. Es lo mismo que suspender el vi sesión, ejecutando un comando, redirigiendo su salida a un archivo temporal, reanudando su vi y leyendo el contenido del archivo temporal.
Aún más potentes son los !
(bang) y :... !
( ex bang). Estos también ejecutan comandos externos y leen los resultados en el texto actual. Sin embargo, ¡también filtran selecciones de nuestro texto a través del comando! Así podemos ordenar todas las líneas de nuestro archivo usando 1G!Gsort
( G
es el vi "goto"; por defecto va a la última línea del archivo, pero puede ir precedido de un número de línea, como 1, la primera línea). Esto equivale al comando ex variante :1,$!sort
. Los escritores suelen utilizar !
con el sistema Unix fmt o doblar utilidades para reformar o "envolver con palabras" selecciones de texto. Una macro muy común es {!}fmt
(reformular el párrafo actual). Los programadores a veces lo utilizan para ejecutar su código, o sólo partes de él, a través de sangría u otras herramientas de reformateo de código.
Utilizando el :r!
y !
significa que cualquier utilidad o filtro externo puede ser tratado como una extensión de nuestro editor. Ocasionalmente he utilizado estos con scripts que sacaban datos de una base de datos, o con wget o lince comandos que sacan datos de un sitio web, o ssh comandos que sacaban datos de sistemas remotos.
Otra utilidad ex comando es :so
(abreviatura de :source
). Esto lee el contenido de un archivo como una serie de comandos. Cuando se inicia vi normalmente, de forma implícita, realiza una :source
en ~/.exinitrc
(y Vim suele hacer esto en ~/.vimrc
(naturalmente). La utilidad de esto es que puedes cambiar tu perfil de editor sobre la marcha simplemente introduciendo un nuevo conjunto de macros, abreviaturas y ajustes del editor. Si eres astuto puedes incluso utilizar esto como un truco para almacenar secuencias de ex comandos de edición para aplicar a los archivos bajo demanda.
Por ejemplo, tengo un archivo de siete líneas (36 caracteres) que ejecuta un archivo a través de wc e inserta un comentario de estilo C en la parte superior del archivo que contiene los datos del recuento de palabras. Puedo aplicar esa "macro" a un archivo usando un comando como vim +'so mymacro.ex' ./mytarget
(El +
opción de línea de comandos para vi y Vim se utiliza normalmente para iniciar la sesión de edición en un número de línea determinado. Sin embargo, es un hecho poco conocido que se puede seguir el +
por cualquier ex comando/expresión, como un comando "fuente" como he hecho aquí; para un ejemplo simple tengo scripts que invocan: vi +'/foo/d|wq!' ~/.ssh/known_hosts
para eliminar una entrada de mi archivo de hosts conocidos de SSH de forma no interactiva mientras reimagino un conjunto de servidores).
Normalmente es mucho más fácil escribir estas "macros" utilizando Perl, AWK, sed (que es, de hecho, como grep una utilidad inspirada en el ed comando).
El @
es probablemente el comando más oscuro vi comando. Al impartir ocasionalmente cursos avanzados de administración de sistemas durante casi una década, he conocido a muy pocas personas que lo hayan utilizado alguna vez. @
ejecuta el contenido de un registro como si fuera un vi o ex comando.
Ejemplo: Suelo usar: :r!locate ...
para encontrar algún archivo en mi sistema y leer su nombre en mi documento. A partir de ahí, elimino los resultados extraños, dejando sólo la ruta completa del archivo que me interesa. En lugar de trabajar Tab -(o peor aún, si me encuentro en una máquina sin soporte para la finalización de pestañas en su copia de vi ) Yo sólo uso:
0i:r
(para convertir la línea actual en una línea válida :r comando),
"cdd
(para borrar la línea en el registro "c") y
@c
ejecutar ese comando.
Son sólo 10 pulsaciones (y la expresión "cdd
@c
es efectivamente una macro de dedo para mí, así que puedo escribirla casi tan rápido como cualquier palabra común de seis letras).
Un pensamiento aleccionador
Sólo he arañado la superficie de vi y nada de lo que he descrito aquí es siquiera parte de las "mejoras" por las que vim ¡es nombrado! Todo lo que he descrito aquí debería funcionar en cualquier copia antigua de vi de hace 20 o 30 años.
Hay personas que han utilizado considerablemente más de vi de lo que yo nunca lo haré.