Общие предостережения
Наиболее распространенный способ обойти проблему файла, доступного только для чтения, - открыть канал для текущего файла в качестве суперпользователя, используя реализацию sudo tee
. Тем не менее, все самые популярные решения, которые я нашел в Интернете, имеют несколько возможных предостережений:
- Весь файл записывается в терминал, а также файл. Это может быть медленно для больших файлов, особенно по медленным сетевым соединениям.
- Файл теряет свои режимы и похожие атрибуты.
- Пути к файлам с необычными символами или пробелами могут обрабатываться неправильно.
Решения
Чтобы обойти все эти проблемы, вы можете использовать следующую команду:
" 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
приглашение -like, которое появляется после запуска :!
команды.
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