¿Líneas duplicadas que comienzan con "x", reemplazando "x" en el duplicado con "y"?

9

Tengo un archivo con el siguiente patrón:

foo 111
baz
foo 222
baz
foo 333
baz

que necesita ser convertido en

foo 111
bar 111
baz
foo 222
bar 222
baz
foo 333
bar 333
baz

Entonces, duplique todas las líneas que comienzan con foo, y cambie solo fooen el duplicado, pero deje intacto el resto de la línea (que difiere en cada caso). ¿Como hacer esto?

LB7979
fuente
Si no estás atado al infierno en una expresión regular, una macro funcionará bien. Realmente no importa mucho en casos simples como este, pero si tienes algo un poco más complicado, es una alternativa muy válida.
PhilippFrank

Respuestas:

19

Aqui tienes:

:g/foo/t.|s//bar

Descomponiendo:

:g/foo/    " start a global command applied on all lines matching 'foo'
t.         " duplicate the current line (the cursor is now on the new line)
|          " chain a new command
s//bar     " substitute the last searched element with 'bar'

Debido a que el gcomando actualizará el patrón de búsqueda, puede omitir el patrón para reemplazarlo en el comando sustituto. (ref .: :h :gbuscar search pattern).


Versión antigua:

:g/foo/norm! yyp:s/foo/bar^M

Descomponiendo:

:g            start a global command
/foo/         apply only on lines having 'foo'
norm!         execute a normal command
yyp           duplicate the line
:s//bar       replace foo with bar on the line (the duplicated one)
^M            add enter to execute the substitution

Para insertar la ^Mprensa Ctrl+vy enter.

Nota : Originalmente se me ocurrió la versión "anterior", antes de conocer el tcomando. Lo dejaré pero no recomendaré usarlo. El primero es más limpio y directo.

nobe4
fuente
Resuelta, la 'versión más simple' funcionó perfectamente. Sin embargo, la primera versión dio como resultado que la línea duplicada todavía comenzara con foo...
LB7979
extraño, ¿entraste ^Mcomo te expliqué?
nobe4
Mi mal, no leí tan bien. ¡La primera solución también funciona!
LB7979
No sé por qué te molestas en incluir la versión complicada. La versión más simple es ... más simple. ;) (Sin mencionar que cumple con POSIX.) ¿Por qué no ponerlo primero?
Comodín el
1
Inicialmente se me ocurrió la primera versión, que era más natural para mí, porque en ese momento no estaba al tanto t, y luego agregué la segunda. Cambiaré el orden, tienes razón. ¿Qué tal si el primero es POSIX?
nobe4
1

Hago cosas como esta todo el tiempo y simplemente hago algo como %s/^foo \(.*\)/foo \1\rbar \1/(en parte porque también hago muchas tareas similares que no se pueden convertir en algo inteligente usando una función de copia, y ahora \(.*\)es parte de mi memoria muscular).

Sospecho que no es compatible con POSIX (no funciona en otros clones vi), pero usar ^M( C-VReturn) en lugar de \rparece funcionar en la mayoría de los otros clones vi.

Aleatorio832
fuente