Come utilizzare l'espansione backtick per popolare l'arglista?


11

Dall'aiuto :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.

Se digito il comando preso dall'aiuto, ricevo un errore:

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

Perché l'esempio della guida utilizza due barre rovesciate anziché una e perché non funziona?

Il seguente lavoro:

  • Se rimuovo una delle due barre rovesciate che proteggono la stella dall'espansione della shell prima del findprogramma:

    :next `find . -name ver\*.c -print`
    
  • Se rimuovo entrambe le barre rovesciate e inserisco virgolette singole attorno al modello ver*.c:

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

Fino a questo punto, la regola sembra essere:
se il comando della shell contiene una stella e non si desidera che la shell la espanda prima del comando, mettere una barra rovesciata davanti o inserire virgolette singole attorno al modello .

Ma l'aiuto fornisce un altro esempio:

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

Questo comando funziona senza alcuna modifica, senza bisogno di virgolette singole, senza necessità di barra rovesciata.
Suppongo che il motivo per cui funziona è perché il lscomando (contrariamente -nameall'argomento del findcomando) accetta più argomenti di file e non vede alcun problema con l'espansione della shell *.patch.

Ora, diciamo che voglio cercare tutti i file con l'estensione .confall'interno della /etccartella e convoglia l'output di findto grepper ottenere solo le corrispondenze contenenti la stringa input.
Nella shell, da qualsiasi directory di lavoro, digitare:

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

E funzionerebbe.

In vim, digiterò lo stesso comando inserendovi backtick e una barra rovesciata davanti al simbolo della pipe per impedire a vim di interpretarlo come terminazione del comando:

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

E funziona

Ora, se digito lo stesso comando senza pipe e il grep input, ottengo un errore:

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

Perché c'è un errore in questo caso anche se ho protetto la stella con virgolette singole?
E perché ora c'è un errore, ma non solo prima con la pipe e il grep input?

Per provare a capire, ho escogitato un comando più semplice:

find . -name '*.conf'

Cerca tutti i file con l'estensione .confnella directory di lavoro. Il comando funziona nella shell.

Per testarlo in vim, ho scritto: :next `find . -name '*.conf'`
E funziona. In questo caso il punto indica la mia directory di lavoro corrente, come visualizzato dal comando Ex, :pwdche è la mia directory home da /home/usernamequando ho avviato la sessione vim da essa.

Perché funziona quando chiedo di cercare nella directory di lavoro corrente mentre non funziona quando chiedo di cercare in una cartella arbitraria come /etc?

Ora, se cambio la mia directory di lavoro da /home/usernamea /etccon il comando vim Ex :cd /etce riprovo lo stesso comando di prima, di nuovo si sbaglia:

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

Perché lo stesso comando funziona quando sono nella mia cartella home ma non quando ci sono /etc?

Sono sicuro che c'è della logica, ma non riesco a trovarne uno.

Qual è la sintassi generale e corretta per popolare l'arglist con un comando shell arbitrario (contenente una stella, una pipe, cercando in qualsiasi directory da qualsiasi directory di lavoro)?

Sto usando vim versione 7.4.942 e zsh è la mia shell predefinita. Ho testato questi comandi con un minimo di inizializzazioni ( vim -u NORC -N) da bash e da zsh.

Devo configurare vim per chiamare bash e non zsh?


Mi chiedo se hai provato ad avviare vim con tutti quei file passati come argomenti? Intendo qualcosa del tipo:vim $(find . -name ver*.c)
Vlad GURDIGA,

@VladGURDIGA Ho appena provato e tutti funzionano come previsto dalla shell: 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 Ma vorrei sapere come popolare l'arglista senza uscire dalla sessione corrente, poiché di solito ne ho solo una. Potrei anche spostarmi nella shell, cercare un gruppo di file e inviarli a un server Vim (con l'argomento --remote, vedi: vi.stackexchange.com/a/5618/4939 ) ma sono curioso di sapere come fallo direttamente dalla sessione corrente. Se non è possibile, va bene, ma dopo aver letto l'aiuto sembra che possa essere fatto. Se lo è, vorrei capire perché vim reagisce in modo così diverso a comandi simili.
Saginaw

Ehi, sembra che nel primo comando di esempio manchi il backtick di chiusura. ;) A parte questo, suppongo che l'esempio della guida usi due barre rovesciate anziché una per impedire l'espansione della shell, come spiegato qui: unix.stackexchange.com/q/104260/23669 .
Vlad GURDIGA,

Nel caso in cui find /etc -name '*.conf'non funzionasse, penso che alcuni nomi divertenti escano da quel comando e, questo potrebbe essere il motivo per cui ha funzionato quando è stato inviato grep.
Vlad GURDIGA,

Risposte:


6

Non so ancora come usare l'espansione backtick per popolare l'arglist con un comando shell arbitrario, tuttavia ho trovato una soluzione alternativa.

Da :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.

Quindi, invece di espandere direttamente un comando shell come questo:

:args `shell command`

Possiamo inviare il comando shell alla funzione Vim systemlist()e usare il registro delle espressioni =per espandere l'espressione risultante in questo modo:

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

Per salvare alcune sequenze di tasti, ho definito il seguente comando Ex nel mio vimrc ( :PAper Populate Arglist):

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

E testato con vari comandi di 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

Finora funziona come previsto e il comando può essere digitato come sarebbe nella shell (ad esempio non è necessario sfuggire alla pipe).
Sembra più coerente e affidabile dell'espansione backtick diretta.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.