Общие предостережения
Наиболее распространенный способ обойти проблему файла, доступного только для чтения, - открыть канал для текущего файла в качестве суперпользователя, используя реализацию sudo tee
. Тем не менее, все самые популярные решения, которые я нашел в Интернете, имеют несколько возможных предостережений:
- Весь файл записывается в терминал, а также файл. Это может быть медленно для больших файлов, особенно для медленных сетевых подключений.
- Файл теряет свои режимы и похожие атрибуты.
- Пути к файлам с необычными символами или пробелами могут обрабатываться неправильно.
* Решения 1014 *
Чтобы обойти все эти проблемы, вы можете использовать следующую команду:
" On POSIX (Linux/Mac/BSD):
:silent execute 'write !sudo tee ' . shellescape(@%, 1) . ' >/dev/null'
" Depending on the implementation, you might need this on Windows:
:silent execute 'write !sudo tee ' . shellescape(@%, 1) . ' >NUL'
Они могут быть сокращены, с уважением:
:sil exec 'w !sudo tee ' . shellescape(@%, 1) . ' >/dev/null'
:sil exec 'w !sudo tee ' . shellescape(@%, 1) . ' >NUL'
Объяснение
:
начинает команду; вам нужно будет ввести этот символ в обычном режиме, чтобы начать ввод команды. Это должно быть опущено в скриптах.
sil[ent]
подавляет вывод команды. В этом случае мы хотим остановить приглашение Press any key to continue
, которое появляется после выполнения команды :!
.
exec[ute]
выполняет строку как команду. Мы не можем просто запустить :write
, потому что он не обработает необходимый вызов функции.
!
представляет команду :!
: единственная команда, которую принимает :write
. Обычно :write
принимает путь к файлу для записи. :!
самостоятельно запускает команду в оболочке (например, используя bash -c
). С :write
он запустит команду в оболочке, а затем запишет весь файл в stdin
.
sudo
должно быть очевидно, потому что именно поэтому вы здесь. Запустите команду как суперпользователь. В сети есть много информации о том, как это работает.
tee
трубы stdin
к данному файлу. :write
запишет в stdin
, затем суперпользователь tee
получит содержимое файла и запишет файл. Он не создаст новый файл - просто перезапишите его содержимое, поэтому режимы и атрибуты файла будут сохранены.
shellescape()
экранирует специальные символы в указанном пути к файлу в зависимости от текущей оболочки. С одним параметром он обычно заключает путь в кавычки по мере необходимости. Поскольку мы отправляем в командную строку полной оболочки, мы хотим передать ненулевое значение в качестве второго аргумента, чтобы включить экранирование от обратной косой черты других специальных символов, которые в противном случае могли бы вызвать сбой оболочки.
@%
читает содержимое регистра %
, который содержит имя файла текущего буфера. Это не обязательно абсолютный путь, поэтому убедитесь, что вы не изменили текущий каталог. В некоторых решениях вы увидите, что рекламный символ опущен. В зависимости от местоположения %
является допустимым выражением и имеет тот же эффект, что и чтение регистра %
. Однако во вложенном выражении ярлык обычно не разрешен: например, в этом случае.
>NUL
и >/dev/null
перенаправляют stdout
на нулевое устройство платформы. Несмотря на то, что мы отключили команду, мы не хотим, чтобы все накладные расходы, связанные с передачей stdin
, возвращались обратно в vim - лучше всего сбросить ее как можно раньше. NUL
- это нулевое устройство в DOS, MS-DOS и Windows, а не допустимый файл. Начиная с Windows 8 перенаправления на NUL не приводят к записи файла с именем NUL. Попробуйте создать файл на рабочем столе с именем NUL, с расширением или без него: вы не сможете это сделать. (В Windows есть несколько других имен устройств, о которых стоит узнать.)
~ / .vimrc
В зависимости от платформы
Конечно, вы все еще не хотите запоминать их и каждый раз печатать их. Гораздо проще сопоставить соответствующую команду с более простой пользовательской командой. Чтобы сделать это в POSIX, вы можете добавить следующую строку в ваш файл ~/.vimrc
, создав его, если он еще не существует:
command W silent execute 'write !sudo tee ' . shellescape(@%, 1) . ' >/dev/null'
Это позволит вам ввести команду: W (с учетом регистра), чтобы записать текущий файл с правами суперпользователя - гораздо проще.
Платформа-Независимый
Я использую независимый от платформы файл ~/.vimrc
, который синхронизируется между компьютерами, поэтому я добавил к своим функциям мультиплатформенность. Вот ~/.vimrc
только с соответствующими настройками:
#!vim
" Use za (not a command; the keys) in normal mode to toggle a fold.
" META_COMMENT Modeline Definition: {{{1
" vim: ts=4 sw=4 sr sts=4 fdm=marker ff=unix fenc=utf-8
" ts: Actual tab character stops.
" sw: Indentation commands shift by this much.
" sr: Round existing indentation when using shift commands.
" sts: Virtual tab stops while using tab key.
" fdm: Folds are manually defined in file syntax.
" ff: Line endings should always be <NL> (line feed #09).
" fenc: Should always be UTF-8; #! must be first bytes, so no BOM.
" General Commands: User Ex commands. {{{1
command W call WriteAsSuperUser(@%) " Write file as super-user.
" Helper Functions: Used by user Ex commands. {{{1
function GetNullDevice() " Gets the path to the null device. {{{2
if filewritable('/dev/null')
return '/dev/null'
else
return 'NUL'
endif
endfunction
function WriteAsSuperUser(file) " Write buffer to a:file as the super user (on POSIX, root). {{{2
exec '%write !sudo tee ' . shellescape(a:file, 1) . ' >' . GetNullDevice()
endfunction
" }}}1
" EOF