Привет, коллеги. Обсудим взаимодействие с оболочкой в смысле имен файлов и файловых масок. Всё сказанное относится к unix-подобным системам: под Windows всё тоже можно, но есть своя специфика, в которую я не углубляюсь.
Файловые маски - это что-то вроде упрощенных регулярных выражений, с метасимволами вроде "любой символ" и "любой текст".
Когда мы употребляем файловые маски в командной строке Вим, они раскрываются. Можно раскрыть их и самостоятельно, получив имя файла (или имена файлов) с помощью функции expand. Функция эта позволяет расшифровать специальные символы (маски) в именах файлов, среди которых самые распространенные - это * и ?, означающие "любое число любых символов" и "один произвольный символ". Так, *.* означает "любой файл с расширением", *.txt — любой текстовый файл, ?.??? — файл с именем из одной буквы и расширением из трех, и так далее. Помним, что * совпадает и с нулем символов, то есть *italian* совпадет и с my_italian_poesy, и просто с italian.
Менее известна конструкция [abc], которая похожа на символьный класс регулярных выражений и им и является: это любой один символ из перечисленных. Так, *[1-9].dat — файл с данным расширением, у которого имя кончается на цифру.
Самая сложная маска — это **. Большого смысла трактовать это как две маски * подряд, нет. Это означает "что угодно", но применяется рекурсивно к каталогам. До ста каталогов в глубину. Так, **/файл.txt совпадет с данным файлом в текущем каталоге и любом его подкаталоге, включая вложенные. А просто */файл.txt совпадет только с файлом в подкаталоге. Если обычный символ стоит сразу после или непосредственно перед **, то этот текст должен совпасть только в имени каталога верхнего уровня. То есть, /usr/inc**/file.inc будет найден в /usr/include и его подкаталогах, а также в каталоге /usr/inc/ и его подкаталогах, в каталоге /usr/increase и в его подкаталогах, и т.п. Это довольно удобно, на самом деле, если освоить.
Функция expand возвращает строку с именем файла, подпадающим под маску, которую вы указали. Если файлов много, их имена разделены символом новой строки.
Например, expand("*.tex") или expand("**/*.tex").
Можно раскрывать и переменные окружения, например, expand($PATH).
Есть и магия. Если выражение начинается с %, решетки или <, то оно трактуется по-особенному. Символ % означает "текущий файл", решетка означает "другой файл", решетка с номером — другой файл по номеру, и есть еще символы. Вот некоторые из них:
- <cfile> — имя файла под курсором (может потребовать дополнительной расшифровки, скажем, если там ~/file.txt)
- <slnum> — номер строки в файле скрипта или функции
Можно употреблять модификаторы, с которыми мы уже знакомы:
- :p — дополнить имя файла до полного пути
- :h — путь (отцепляется последний элемент пути)
- :t — файл (оставляется последний элемент пути)
- :r — отцепляется расширение
- :e — оставляется только расширение
- :. — путь относительно текущего каталога (если можно). Например, если файл лежит в /home/math/dissert/pics/scheme.eps, а мы находимся в /home/math/dissert, то получим pics/scheme.eps
- :~ — то же относительно домашнего каталога.
- :s?pat?sub? заменяет первое вхождение pat на sub, причем pat — регулярное выражение. Разделитель может быть и другой: любой другой символ, только его не должно быть между.
- :gs?pat?sub? — то же самое, но заменяет все вхождения.
:S — действует, как shellescape (см. далее).
Например, я открываю файл:
:tabnew ../1.bib
Даю команду :echo expand('%')
Получаю /home/math/1.bib — то же, что даст и %:p
:echo expand('%:h') — /home/math/
:echo expand('%:t') — 1.bib
:echo expand('%:r') — 1
:echo expand('%:e') — bib
Модификаторы можно комбинировать.
А можно же expand('%:r') . '.tex' — поменять расширение.
А можно сделать это проще: expand('%:s?bib?tex?').
Функция escape принимает две строки и позволяет экранировать (снабдить слешем \) все символы, перечисленные во втором аргументе.
Например, escape('***', '*') вернет '\*\*\*'
Это функция общего назначения, а есть более специфичная shellescape, которая готовит строку к использованию в командной строке оболочки.
Она поместит строку в одинарные кавычки и заменит все такие кавычки внутри на '\'' (именно кавычка слеш две кавычки).
Если присутствует второй аргмент и это не нуль и не пустая строка, то экранируются также символы !, % и некоторые другие.
Примеры:
:exe '!ls ' . shellescape(expand('<cfile>:h'), 1)
:call system("chmod +w -- " . shellescape(expand("%")))
Можно избежать прямого вызова shellescape, применив модификатор :S, если модификаторы уместны.
Вернемся к командной строке Вим. Помимо файловых масок, можно применять еще обратные кавычки `...` (кавычка эта обычно слева сверху на клавиатуре, где тильда и буквы Ё). Их содержимое будет выполнено оболочкой, а команда Вим получит ее результат. Примеры из Справки:
:next `find . -name ver\\*.c -print`
:view `ls -t *.patch \| head -n1`
Слеши перед звездочкой нужны, чтобы оболочка не раскрыла маску, а передала ее команде find.
Это применение обратных кавычек стандартно: так же они используются в bash, Перл и не только.
И вы понимаете, что это небезопасно, особенно если вы вызываете что-то не своё.
В Вим есть особенность: если после обратной кавычки стоит знак равенства, то выражение в обратных кавычках вычисляется как выражение Вим.
Это позволяет, в частности, вызывать любые функции, так что можно делать вообще, что хотите:
:tabnew `=MyFileName()`
Функция MyFileName должна вернуть имя файла. Можете, например, запрашивать пароль))
Но это уже другая история...