command-line – ¿Cómo usar la expansión de comillas invertidas para poblar el arglist?

Pregunta:

De ayuda :help backtick-expansion :

On Unix and a few other systems you can also use backticks for the file name
argument, for example:
    :next `find . -name ver\\*.c -print`
    :view `ls -t *.patch  \| head -n1`
The backslashes before the star are required to prevent the shell from
expanding "ver*.c" prior to execution of the find program.  The backslash
before the shell pipe symbol "|" prevents Vim from parsing it as command
termination.

Si escribo el comando tomado de la ayuda, aparece un error:

:next `find . -name ver\\*.c -print
E79: Cannot expand wildcards  

¿Por qué el ejemplo de la ayuda usa dos barras invertidas en lugar de una y por qué no funciona?

El siguiente trabajo:

  • Si elimino una de las dos barras diagonales inversas que protegen a la estrella de ser expandida por el shell antes del programa de find :

     :next `find . -name ver\*.c -print`
  • Si elimino ambas barras diagonales inversas y pongo comillas simples alrededor del patrón ver*.c :

     :next `find . -name 'ver*.c' -print`

Hasta este punto, la regla parece ser:
Si su comando de shell contiene una estrella y no desea que el shell lo expanda antes del comando, coloque una barra invertida delante de él o entre comillas simples alrededor del patrón .

Pero la ayuda da otro ejemplo:

:view `ls -t *.patch  \| head -n1`

Este comando funciona sin ninguna modificación, sin necesidad de comillas simples, sin necesidad de barra invertida.
Supongo que la razón por la que funciona es porque el comando ls (contrariamente al argumento -name del comando find ) acepta múltiples argumentos de archivo y no ve ningún problema con la expansión del shell *.patch .

Ahora, digamos que quiero buscar todos los archivos con la extensión .conf dentro de la carpeta /etc y canalizar la salida de find a grep para obtener solo las coincidencias que contienen la input la cadena.
En el shell, desde cualquier directorio de trabajo, escribiría:

find /etc -name '*.conf' | grep input

Y funcionaría.

En vim, escribiré el mismo comando colocando comillas inversas a su alrededor y una barra invertida delante del símbolo de la tubería para evitar que vim lo interprete como una terminación de comando:

:next `find /etc -name '*.conf' \| grep input`

Y funciona.

Ahora, si escribo el mismo comando sin la tubería y la grep input , aparece un error:

:next `find /etc -name '*.conf'`
E79: Cannot expand wildcards

¿Por qué hay un error en este caso aunque protegí la estrella con comillas simples?
¿Y por qué hay un error ahora, pero no justo antes con la tubería y la grep input ?

Para intentar comprender, se me ocurrió un comando más simple:

find . -name '*.conf'

Busca todos los archivos con extensión .conf en el directorio de trabajo. El comando funciona en el shell.

Para probarlo en vim, escribí :next `find . -name '*.conf'`
Y funciona. En este caso, el punto representa mi directorio de trabajo actual como se muestra en el comando Ex :pwd que es mi directorio de /home/username desde que inicié la sesión vim desde él.

¿Por qué funciona cuando pido buscar en el directorio de trabajo actual mientras que no funciona cuando pido buscar en una carpeta arbitraria como /etc ?

Ahora, si cambio mi directorio de trabajo de /home/username a /etc con el comando vim Ex :cd /etc y vuelvo a intentar el mismo comando que antes, nuevamente aparece un error:

:next `find . -name '*.conf'`
E79: Cannot expand wildcards

¿Por qué funciona el mismo comando cuando estoy en mi carpeta de inicio pero no cuando estoy en /etc ?

Estoy seguro de que hay algo de lógica, pero no puedo encontrar una.

¿Cuál es la sintaxis general y correcta para poblar el arglist con un comando de shell arbitrario (que contiene una estrella, una tubería, buscando en cualquier directorio desde cualquier directorio de trabajo)?

Estoy usando vim versión 7.4.942 y zsh es mi shell predeterminado. Probé estos comandos con un mínimo de inicializaciones ( vim -u NORC -N ) tanto desde bash como desde zsh.

¿Necesito configurar vim para llamar a bash y no a zsh?

Respuesta:

Todavía no sé cómo usar la expansión de comillas invertidas para completar el arglist con un comando de shell arbitrario, sin embargo, encontré una solución.

De :help `= :

You can have the backticks expanded as a Vim expression, instead of as an
external command, by putting an equal sign right after the first backtick,
e.g.:
    :e `=tempname()`
The expression can contain just about anything, thus this can also be used to
avoid the special meaning of '"', '|', '%' and '#'.  However, 'wildignore'
does apply like to other wildcards.

Entonces, en lugar de expandir directamente un comando de shell como este:

:args `shell command`

Podemos enviar el comando de shell a la función Vim systemlist() y usar la expresión register = para expandir la expresión resultante de esta manera:

:args `=systemlist("shell command")`

Para guardar algunas pulsaciones de teclas, definí el siguiente comando Ex en mi vimrc ( :PA para Populate Arglist):

command! -nargs=1 PA args `=systemlist(<q-args>)`

Y lo probé con varios comandos de shell:

:PA find . -name ver\*.c -print 2>/dev/null
:PA find . -name 'ver*.c' -print 2>/dev/null
:PA ls -t *.patch  | head -n1
:PA find /etc -name '*.conf' 2>/dev/null | grep input
:PA find /etc -name '*.conf' 2>/dev/null
:PA find . -name '*.conf' 2>/dev/null

Hasta ahora, funciona como se esperaba y el comando se puede escribir como estaría en el shell (no es necesario escapar de la tubería, por ejemplo).
Parece más consistente y confiable que la expansión directa con comillas invertidas.

Leave a Comment

Your email address will not be published.

Scroll to Top

istanbul avukat

-

web tasarım