Comment utiliser l'expansion backtick pour remplir l'arglist?

11

De l'aide :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 je tape la commande tirée de l'aide, j'obtiens une erreur:

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

Pourquoi l'exemple de l'aide utilise-t-il deux barres obliques inverses au lieu d'une, et pourquoi cela ne fonctionne-t-il pas?

Le travail suivant:

  • Si je supprime l'une des deux barres obliques inverses qui protègent l'étoile d'être étendue par le shell avant le findprogramme:

    :next `find . -name ver\*.c -print`
    
  • Si je supprime les deux barres obliques inverses et place des guillemets simples autour du motif ver*.c:

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

Jusqu'à présent, la règle semble être la suivante:
si votre commande shell contient une étoile et que vous ne voulez pas que le shell la développe avant la commande, placez une barre oblique inverse devant elle ou mettez des guillemets simples autour du motif .

Mais l'aide donne un autre exemple:

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

Cette commande fonctionne sans aucune modification, pas besoin de guillemets simples, pas besoin de barre oblique inverse.
Je suppose que la raison pour laquelle cela fonctionne est que la lscommande (contrairement à l' -nameargument de la findcommande) accepte plusieurs arguments de fichier et ne voit aucun problème avec l'expansion du shell *.patch.

Maintenant, disons que je veux rechercher tous les fichiers avec l'extension .confdans le /etcdossier et redirige la sortie de findvers greppour obtenir uniquement les correspondances contenant la chaîne input.
Dans le shell, à partir de n'importe quel répertoire de travail, je tape:

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

Et ça marcherait.

Dans vim, je vais taper la même commande en le mettant en arrière et une barre oblique inverse devant le symbole du tuyau pour empêcher vim de l'interpréter comme une terminaison de commande:

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

Et il fonctionne.

Maintenant, si je tape la même commande sans le pipe et le grep input, j'obtiens une erreur:

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

Pourquoi y a-t-il une erreur dans ce cas même si j'ai protégé l'étoile avec des guillemets simples?
Et pourquoi y a-t-il une erreur maintenant, mais pas juste avant avec le tuyau et le grep input?

Pour essayer de comprendre, j'ai trouvé une commande plus simple:

find . -name '*.conf'

Il recherche tous les fichiers avec l'extension .confdans le répertoire de travail. La commande fonctionne dans le shell.

Pour le tester dans vim, j'ai tapé: :next `find . -name '*.conf'`
Et ça marche. Dans ce cas, le point représente mon répertoire de travail actuel tel qu'affiché par la commande Ex :pwdqui est mon répertoire personnel /home/usernamedepuis que j'ai lancé la session vim à partir de celui-ci.

Pourquoi ça marche quand je demande de chercher dans le répertoire de travail courant alors que ça ne marche pas quand je demande de chercher dans un dossier arbitraire comme /etc?

Maintenant, si je change mon répertoire de travail de en /home/usernameà l' /etcaide de la commande vim Ex :cd /etcet réessaye la même commande qu'avant, encore une fois il se trompe:

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

Pourquoi la même commande fonctionne-t-elle lorsque je suis dans mon dossier de départ mais pas quand je le suis /etc?

Je suis sûr qu'il y a une certaine logique, mais je n'en trouve pas.

Quelle est la syntaxe générale et correcte pour remplir l'arglist avec une commande shell arbitraire (contenant une étoile, un canal, la recherche dans n'importe quel répertoire depuis n'importe quel répertoire de travail)?

J'utilise la version 7.4.942 de vim et zsh est mon shell par défaut. Je l' ai testé ces commandes avec un minimum de initialisations ( vim -u NORC -N) de bash, ainsi que de zsh.

Dois-je configurer vim pour appeler bash et non zsh?

saginaw
la source
Je me demande si vous avez essayé de démarrer vim avec tous ces fichiers passés en arguments? Je veux dire quelque chose comme:vim $(find . -name ver*.c)
Vlad GURDIGA
@VladGURDIGA J'ai juste essayé et ils travaillent tous comme prévu de la coquille: vim $(find . -name ver\*.c -print), vim $(ls -t *.patch | head -n1), vim $(find /etc -name '*.conf' | grep input), vim $(find /etc -name '*.conf'),vim $(find . -name '*.conf')
saginaw
@VladGURDIGA Mais je voudrais savoir comment remplir l'arglist sans quitter la session en cours car je n'en ai généralement qu'une. Je pourrais aussi vous déplacer dans la coquille, la recherche d'un groupe de fichiers et de les envoyer à un serveur Vim (avec l'argument --remote, voir: vi.stackexchange.com/a/5618/4939 ) mais je suis curieux de savoir comment faites-le directement à partir de la session en cours. Si ce n'est pas possible, c'est bien, mais après avoir lu l'aide, il semble que cela puisse être fait. Si c'est le cas, j'aimerais comprendre pourquoi vim réagit si différemment à des commandes similaires.
saginaw
Hé, il semble que dans le premier exemple de commande, vous manquez le backtick final. ;) En dehors de cela bien, je suppose que l'exemple de l'aide , utilisez deux barres obliques inverses au lieu d'un pour empêcher l' expansion shell, comme expliqué ici: unix.stackexchange.com/q/104260/23669 .
Vlad GURDIGA
Dans le cas de find /etc -name '*.conf'ne pas fonctionner, je pense que certains noms drôles sortent de cette commande, et c'est peut-être la raison pour laquelle cela a fonctionné une fois redirigé grep.
Vlad GURDIGA

Réponses:

6

Je ne sais toujours pas comment utiliser backtick-expansion pour remplir l'arglist avec une commande shell arbitraire, mais j'ai trouvé une solution de contournement.

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.

Ainsi, au lieu d'étendre directement une commande shell comme celle-ci:

:args `shell command`

Nous pouvons envoyer la commande shell à la fonction Vim systemlist()et utiliser le registre d'expression =pour développer l'expression résultante comme ceci:

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

Pour enregistrer certaines séquences de touches, j'ai défini la commande Ex suivante dans mon vimrc ( :PApour Populate Arglist):

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

Et je l'ai testé avec diverses commandes 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

Jusqu'à présent, cela fonctionne comme prévu et la commande peut être tapée comme elle le serait dans le shell (pas besoin d'échapper au pipe par exemple).
Il semble plus cohérent et fiable que l'expansion directe en backtick.

saginaw
la source