Tu problema con Vim es que no entiendes vi .
Menciona cortar con yy
y se queja de que casi nunca quiere cortar líneas enteras. De hecho, los programadores, que editan 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 solo una de las muchas formas de tirar texto al búfer de copia anónimo (o "registrarse" como se llama en vi ).
El "Zen" de vi es que estás hablando un idioma. La inicial y
es un verbo. La declaración yy
es sinónimo de y_
. Se y
duplica para que sea más fácil escribir, ya que es una operación tan común.
Esto también se puede expresar como dd
P
(eliminar la línea actual y pegar una copia en su lugar; dejando una copia en el registro anónimo como efecto secundario). Las y
y los d
"verbos" toman cualquier movimiento como su "sujeto". Por yW
lo tanto, es "tirar de aquí (el cursor) al final de la palabra actual / siguiente (grande)" y y'a
es "tirar de aquí a la línea que contiene la marca llamada ' a '".
Si solo comprende los movimientos básicos del cursor hacia arriba, hacia abajo, hacia la izquierda y hacia la derecha, vi no será más productivo que una copia del "bloc de notas" para usted. (De acuerdo, aún tendrá resaltado de sintaxis y la capacidad de manejar archivos más grandes que un piddling ~ 45KB más o menos; pero trabaje conmigo aquí).
vi tiene 26 "marcas" y 26 "registros". Una marca se establece en cualquier ubicación del cursor usando el m
comando. Cada marca se designa con una letra minúscula. Por lo tanto, ma
establece la marca ' a ' en la ubicación actual y mz
establece la marca ' z '. Puede moverse a la línea que contiene una marca utilizando el '
comando (comillas simples). Así se 'a
mueve al principio de la línea que contiene la marca ' a '. Puede moverse a la ubicación precisa de cualquier marca utilizando el `
comando (backquote). Por `z
lo tanto, se moverá directamente a la ubicación exacta de la marca ' z '.
Debido a que estos son "movimientos", también pueden usarse como temas para otras "declaraciones".
Entonces, una forma de cortar una selección arbitraria de texto sería soltar una marca (generalmente uso ' a ' como mi "primera" marca, ' z ' como mi siguiente marca, ' b ' como otra y ' e ' como otro más (no recuerdo haber usado interactivamente más de cuatro marcas en 15 años de uso de vi ; una crea las propias convenciones sobre cómo las marcas y los registros son utilizados por las macros que no perturban el contexto interactivo de uno). al otro extremo de nuestro texto deseado; podemos comenzar en cualquier extremo, no importa. Luego podemos simplemente usar d`a
para cortar o y`a
copiar. Por lo tanto, todo el proceso tiene una sobrecarga de 5 teclas (seis si comenzamos en "insertar "modo y necesitabaEscfuera del modo de comando). Una vez que hemos cortado o copiado a continuación, pegar en una copia es una sola tecla: p
.
Digo que esta es una forma de cortar o copiar texto. Sin embargo, es solo uno de muchos. Con frecuencia podemos describir de manera más sucinta el rango de texto sin 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. Entonces, para mover un párrafo de texto, lo corto usando {
d}
(3 pulsaciones de teclas). (Si ya estoy en la primera o última línea del párrafo, entonces simplemente puedo usar d}
o d{
respectivamente.
La noción de "párrafo" por defecto es algo que generalmente es intuitivamente razonable. Por lo tanto, a menudo funciona 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 adelante o hacia atrás son movimientos en vi . Por lo tanto, también pueden usarse como "sujetos" en nuestras "declaraciones". Así que puedo usar d/foo
para cortar de la línea actual a la siguiente línea que contiene la cadena "foo" y y?bar
copiar de la línea actual a la línea más reciente (anterior) que contiene "barra". Si no quiero líneas enteras, todavía puedo usar los movimientos de búsqueda (como declaraciones propias), soltar mis marcas y usar los `x
comandos como se describió anteriormente.
Además de "verbos" y "sujetos", vi también tiene "objetos" (en el sentido gramatical del término). Hasta ahora solo he descrito el uso del registro anónimo. Sin embargo, puedo usar cualquiera de los 26 registros "con nombre" prefijando la referencia "objeto" con "
(el modificador de comillas dobles). Por lo tanto, si lo uso "add
, estoy cortando la línea actual en el registro ' a ' y si lo uso "by/foo
, estoy sacando una copia del texto de aquí a la siguiente línea que contiene "foo" en el " pega una copia de" b registro b '. Para pegar de un registro simplemente el prefijo pasta con la misma secuencia de modificador: "ap
pega una copia de la ' un ' registro'"bP
' a antes de la línea actual.
Esta noción de "prefijos" también agrega los análogos de los "adjetivos" y "adverbios" gramaticales a nuestro lenguaje de manipulación de texto ". La mayoría de los comandos (verbos) y el movimiento (verbos u objetos, dependiendo del contexto) también pueden tomar prefijos numéricos. 3J
significa "unir las siguientes tres líneas" y d5}
significa "eliminar de la línea actual hasta el final del quinto párrafo desde aquí".
Todo esto es nivel intermedio vi . Nada de esto es específico de Vim y hay trucos mucho más avanzados en vi si estás listo para aprenderlos. Si fuera a dominar solo estos conceptos intermedios, probablemente encontraría que rara vez necesita escribir macros porque el lenguaje de manipulación de texto es lo suficientemente conciso y expresivo para hacer la mayoría de las cosas con la suficiente facilidad usando el lenguaje "nativo" del editor.
Una muestra de trucos más avanzados:
Hay una serie de :
comandos, sobre todo la :% s/foo/bar/g
técnica de sustitución global. (Eso no es avanzado pero otros :
comandos pueden serlo). El :
conjunto completo de comandos fue heredado históricamente por las encarnaciones anteriores de vi como ed (editor de líneas) y más tarde las utilidades ex (editor de líneas extendidas). De hecho, vi se llama así porque es la interfaz visual para ex .
:
los comandos normalmente operan sobre líneas de texto. ed y ex se escribieron en una época en la que las pantallas de terminal eran poco comunes y muchos terminales eran dispositivos de "teletipo" (TTY). Por lo tanto, era común trabajar a partir de copias impresas del texto, utilizando comandos a través de una interfaz extremadamente concisa (las velocidades de conexión comunes eran 110 baudios, o, aproximadamente, 11 caracteres por segundo, lo que es más lento que un mecanógrafo rápido; los retrasos eran comunes en sesiones interactivas multiusuario; además, a menudo hubo cierta motivación para conservar el papel).
Entonces, la sintaxis de la mayoría de los :
comandos incluye una dirección o rango de direcciones (número de línea) seguido de un comando. Naturalmente, uno podría usar números de línea literales: :127,215 s/foo/bar
para cambiar la primera aparición de "foo" en "barra" en cada línea entre 127 y 215. También podría usar algunas abreviaturas como .
o $
para las líneas actuales y últimas respectivamente. También se podrían usar prefijos relativos +
y -
referirse a las compensaciones después o antes de la línea de curado, respectivamente. Por :.,$j
lo tanto: significa "desde la línea actual hasta la última línea, únalas todas en una sola línea". :%
es sinónimo de :1,$
(todas las líneas).
Los comandos :... g
y :... v
tienen alguna explicación, ya que son increíblemente poderosos. :... g
es un prefijo para "globalmente" aplicar un comando posterior a todas las líneas que coinciden 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 comandos ex , estos pueden tener el prefijo direccionamiento / referencias de rango. Por :.,+21g/foo/d
lo tanto, significa "eliminar 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, eliminar cualquier línea que NO contenga la cadena" barra ".
Es interesante que el comando grep común de Unix se haya inspirado realmente en este comando ex (y lleva el nombre de la forma en que se documentó). El comando ex:g/re/p
(grep) fue la forma en que documentaron cómo "globalmente" "imprimir" líneas que contienen una "expresión regular" (re). Cuando se usaron ed y ex , el :p
comando fue uno de los primeros que alguien aprendió y, a menudo, el primero que se usó al editar cualquier archivo. Fue así como imprimiste el contenido actual (generalmente solo una página llena 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 otros ex
comandos que vale la pena recordar:
Podemos usar m
para mover líneas y j
unir líneas. Por ejemplo, si tiene una lista y desea separar todas las cosas que coinciden (o, por el contrario, NO coinciden con algún patrón) sin eliminarlas, puede usar algo como: :% g/foo/m$
... y todas las líneas "foo" se habrán movido a El final del archivo. (Tenga en cuenta el otro consejo sobre el uso del final de su archivo como un espacio de memoria virtual). Esto habrá preservado el orden relativo de todas las líneas "foo" mientras las ha extraído del resto de la lista. (Esto sería equivalente a hacer algo como: 1G!GGmap!Ggrep foo<ENTER>1G:1,'a g/foo'/d
(copie el archivo en su propia cola, filtre la cola grep
y elimine todas las cosas de la cabeza).
Para unir líneas, generalmente puedo encontrar un patrón para todas las líneas que deben unirse a su predecesor (todas las líneas que comienzan con "^" en lugar de "^ *" en alguna lista de viñetas, por ejemplo). Para ese caso, usaría: :% g/^ /-1j
(para cada línea coincidente, sube una línea y únete a ellas). (Por cierto: para listas de viñetas tratando de buscar las líneas de bala y unirse a la siguiente no funciona para un par de razones ... que puede unirse a una línea de bala a otro, y no va a unirse a cualquier línea de bala en todo de sus continuaciones; solo funcionará en parejas en los partidos).
Casi no hace falta mencionar que puede usar nuestro viejo amigo s
(sustituto) con los comandos g
y v
(global / converse-global). Por lo general, no necesita hacerlo. Sin embargo, considere algún caso en el que desee realizar una sustitución solo en líneas que coincidan con otro patrón. A menudo puede usar un patrón complicado con capturas y usar referencias posteriores para preservar las partes de las líneas que NO desea 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 todas las "barras" por "zzz". (Algo como:% s/\(.*foo.*\)bar\(.*\)/\1zzz\2/g
solo funcionaría para los casos de instancias de "barra" que fueron PREDEDADAS por "foo" en la misma línea; ya es bastante desgarbado, y habría que destrozarlo más para detectar todos los casos en que "bar" precedió a "foo")
El punto es que no son más que simples p
, s
y d
líneas en el ex
conjunto de comandos.
Las :
direcciones también pueden referirse a marcas. Por lo tanto, puede usar: :'a,'bg/foo/j
para unir cualquier línea que contenga la cadena foo a su línea posterior, si se encuentra entre las líneas entre las marcas ' a ' y ' b '. (Sí, todos los ex
ejemplos de comandos anteriores se pueden limitar a subconjuntos de las líneas del archivo con el prefijo de este tipo de expresiones de direccionamiento).
Eso es bastante oscuro (solo he usado algo así unas pocas veces en los últimos 15 años). Sin embargo, admitiré libremente que a menudo he hecho cosas de forma iterativa e interactiva que probablemente podrían haberse hecho de manera más eficiente si me hubiera tomado el tiempo para pensar en el encantamiento correcto.
Otro comando vi o ex muy útil es :r
leer el contenido de otro archivo. Por lo tanto: :r foo
inserta el contenido del archivo llamado "foo" en la línea actual.
Más poderoso es el :r!
comando. Esto lee los resultados de un comando. Es lo mismo que suspender la sesión vi , ejecutar un comando, redirigir su salida a un archivo temporal, reanudar su sesión vi y leer el contenido de la temp. archivo.
Aún más potentes son los comandos !
(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! Esto podemos ordenar todas las líneas en nuestro archivo usando 1G!Gsort
( G
es el comando vi "goto"; el valor predeterminado es ir 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 es equivalente a la variante ex:1,$!sort
. Los escritores a menudo usan !
las utilidades fmt o fold de Unix para reformatear o "envolver palabras" selecciones de texto. Una macro muy común es{!}fmt
(formatear el párrafo actual). Los programadores a veces lo usan para ejecutar su código, o solo partes de él, a través de sangría u otras herramientas de reformateo de código.
El uso de los comandos :r!
y !
significa que cualquier utilidad o filtro externo puede tratarse como una extensión de nuestro editor. Ocasionalmente los he usado con scripts que extrajeron datos de una base de datos, o con comandos wget o lynx que extrajeron datos de un sitio web, o comandos ssh que extrajeron datos de sistemas remotos.
Otro comando ex útil es :so
(abreviatura de :source
). Esto lee el contenido de un archivo como una serie de comandos. Al iniciar vi normalmente, de manera implícita, realiza una :source
de ~/.exinitrc
archivo (y Vim normalmente lo hace en este ~/.vimrc
, como es natural). El uso de esto es que puede cambiar su perfil de editor sobre la marcha simplemente buscando un nuevo conjunto de macros, abreviaturas y configuraciones de editor. Si eres astuto, incluso puedes usar esto como un truco para almacenar secuencias de comandos de edición ex para aplicar a archivos a pedido.
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 de conteo de palabras. Puedo aplicar esa "macro" a un archivo usando un comando como:vim +'so mymacro.ex' ./mytarget
(La +
opción de línea de comando para vi y Vim se usa normalmente para iniciar la sesión de edición en un número de línea dado. Sin embargo, es un hecho poco conocido que uno puede seguir +
cualquier comando / expresión ex válido , como un comando "fuente" como Lo 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 estoy volviendo a generar imágenes de un conjunto de servidores).
Por lo general, es mucho más fácil escribir tales "macros" usando Perl, AWK, sed (que, de hecho, es como grep, una utilidad inspirada en el comando ed ).
El @
comando es probablemente el comando vi más oscuro . Al enseñar ocasionalmente cursos avanzados de administración de sistemas durante casi una década, he conocido a muy pocas personas que lo hayan usado. @
ejecuta el contenido de un registro como si fuera un comando vi o ex .
Ejemplo: a menudo uso: :r!locate ...
para encontrar algún archivo en mi sistema y leer su nombre en mi documento. A partir de ahí, elimino cualquier golpe extraño, dejando solo la ruta completa al archivo que me interesa. En lugar de Tabpasar laboriosamente a través de cada componente de la ruta (o peor, si estoy atascado en una máquina sin soporte para completar Tab) en su copia de vi ) solo uso:
0i:r
(para convertir la línea actual en un comando válido : r ),
"cdd
(para eliminar la línea en el registro "c") y
@c
ejecutar ese comando
Eso es solo 10 pulsaciones de teclas (y la expresión "cdd
@c
es efectivamente una macro de dedo para mí, por lo que puedo escribirla casi tan rápido como cualquier palabra común de seis letras).
Un pensamiento aleccionador
¡Solo he arañado a la superficie el poder de vi y nada de lo que he descrito aquí es parte de las "mejoras" por las cuales se nombra vim ! 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 usado considerablemente más poder de vi que yo.