Як використовувати backtick-extension для заповнення аргументу?


11

З довідки :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.

Якщо я введіть команду, взяту з довідки, я отримаю помилку:

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

Чому в прикладі довідки використовується два зворотних риски замість одного, і чому це не працює?

Наступна робота:

  • Якщо я видаляю один із двох кутів, які захищають зірку від розширення оболонкою перед findпрограмою:

    :next `find . -name ver\*.c -print`
    
  • Якщо я видаляю обидві нахили в нижній частині накиду і розміщую окремі лапки навколо шаблону ver*.c:

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

До цього моменту, здається, правило:
якщо ваша команда оболонки містить зірку, і ви не хочете, щоб оболонка розширювала її перед командою, покладіть один зворотний проріз перед ним або покладіть одинарні лапки навколо шаблону .

Але допомога дає ще один приклад:

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

Ця команда працює без будь-яких модифікацій, не потребує одинарних лапок, немає зворотної косої риси.
Я припускаю, що причина цього працює в тому, що lsкоманда (всупереч -nameаргументу findкоманди) приймає кілька аргументів файлів і не бачить проблем з розширенням оболонки *.patch.

Тепер, давайте скажемо , я хочу , щоб шукати всі файли з розширенням .confвсередині /etcпапки і труб на вихід з findдо grepотримати тільки сірники , що містить рядок input.
У оболонці з будь-якого робочого каталогу я б набрав:

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

І спрацювало б.

У vim я введу ту саму команду, що посилає навколо неї зворотні посилання, і зворотній косий ривок перед символом труби, щоб запобігти інтерпретації Vim як припинення команди:

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

І це працює.

Тепер, якщо я набираю ту саму команду без pipe та the grep input, я отримую помилку:

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

Чому в цьому випадку є помилка, навіть якщо я захистив зірку єдиними цитатами?
І чому зараз є помилка, але не тільки раніше з трубою і grep input?

Щоб спробувати зрозуміти, я придумав більш просту команду:

find . -name '*.conf'

Він шукає всі файли з розширенням .confу робочому каталозі. Команда працює в оболонці.

Щоб перевірити його на vim, я набрав: :next `find . -name '*.conf'`
І це працює. У цьому випадку крапка відповідає моєму поточному робочому каталогу, як показано командою Ex, :pwdяка є моєю домашньою директорією /home/usernameз моменту запуску з неї сеансу vim.

Чому це працює, коли я прошу шукати в поточному робочому каталозі, тоді як він не працює, коли я прошу шукати в довільній папці, наприклад /etc?

Тепер, якщо я міняю свою робочу директорію з /home/usernameна /etcкоманду vim Ex :cd /etcі повторюю ту саму команду, що і раніше, вона знову помиляється:

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

Чому та сама команда працює, коли я перебуваю у своїй домашній папці, але не коли я перебуваю /etc?

Я впевнений, що є якась логіка, але я не можу її знайти.

Який загальний і правильний синтаксис для заповнення аргументу за допомогою довільної команди оболонки (містить зірочку, трубу, пошук у будь-якому каталозі з будь-якого робочого каталогу)?

Я використовую версію vim 7.4.942, а zsh - моя оболонка за замовчуванням. Я перевірив ці команди з мінімальним ініціалізацією ( vim -u NORC -N) як від bash, так і з zsh.

Чи потрібно мені налаштувати vim для виклику bash, а не zsh?


Мені цікаво, чи ви намагалися запустити vim з усіма тими файлами, переданими як аргументи? Я маю на увазі щось на кшталт:vim $(find . -name ver*.c)
Влад ГУРДІГА

@VladGURDIGA Я просто намагався і всі вони працюють , як і очікувалося від оболонки: 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')
Сагіно

@VladGURDIGA Але я хотів би знати, як заповнити аргумент, не виходячи з поточного сеансу, оскільки у мене зазвичай тільки один. Я також міг би пересуватися в оболонці, шукати групу файлів і надсилати їх на сервер Vim (з аргументом --remoteдив.: Vi.stackexchange.com/a/5618/4939 ), але мені цікаво знати, як це зробити робити це безпосередньо з поточного сеансу. Якщо це неможливо, це добре, але, прочитавши допомогу, здається, це можна зробити. Якщо це так, я хотів би зрозуміти, чому vim так по-різному реагує на подібні команди.
saginaw

Гей, здається, що в першій команді зразка вам не вистачає закриваючої підказки. ;) Окрім цього, мабуть, у прикладі довідки використовуються два зворочих косих риски замість одного для запобігання розширення оболонки, як пояснено тут: unix.stackexchange.com/q/104260/23669 .
Влад ГУРДІГА

У випадку, якщо це find /etc -name '*.conf'не працює, я думаю, що з цієї команди виходять якісь кумедні імена, і це може бути причиною того, що воно спрацювало під час проходження grep.
Влад ГУРДІГА

Відповіді:


6

Я досі не знаю, як використовувати розширення backtick для заповнення аргументу за допомогою довільної команди оболонки, однак я знайшов рішення.

Від :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.

Отже, замість розширення безпосередньо команди оболонки, як це:

:args `shell command`

Ми можемо надіслати команду оболонки до функції Vim systemlist()і використовувати регістр виразів =для розширення отриманого вираження таким чином:

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

Для збереження деяких натискань клавіш я визначив таку команду Ex у своєму vimrc ( :PAдля Arglist Populate):

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

І тестували його за допомогою різних команд оболонок:

: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

Поки це працює як очікувалося, і команду можна вводити так, як це було б у оболонці (не потрібно бігти з труби, наприклад).
Це здається більш послідовним і надійним, ніж пряме розширення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.