Получение прав root для файла внутри vi?
Часто, редактируя файлы конфигурации, я открываю один с помощью vi, а затем, когда иду, чтобы сохранить его, понимаю, что я не набирал
sudo vi filename
Есть ли способ предоставить vi sudo привилегии для сохранения файла? Кажется, я припоминаю, что видел что-то об этом, когда искал кое-что о vi некоторое время назад, но теперь я не могу этого найти.
Ответов (10)10
%
заменяется текущим именем файла, поэтому вы можете использовать:
:w !sudo tee %
( vim
обнаружит, что файл был изменен, и спросит, хотите ли вы, чтобы он был перезагружен. Скажите «да», выбрав, [L]
а не «ОК».)
В качестве ярлыка вы можете определить свою собственную команду. Поместите в свой .vimrc
:
command W w !sudo tee % >/dev/null
С помощью вышеуказанного вы можете ввести, :W<Enter>
чтобы сохранить файл. С тех пор, как я написал это, я нашел более приятный (на мой взгляд) способ сделать это:
cmap w!! w !sudo tee >/dev/null %
Таким образом, вы можете ввести текст, :w!!
и он будет расширен до полной командной строки, оставив курсор в конце, так что вы можете заменить его %
собственным именем файла, если хотите.
Общие предостережения
Наиболее распространенный метод решения проблемы файла, доступного только для чтения, - открыть канал к текущему файлу от имени суперпользователя, используя реализацию 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
-подобное приглашение, которое появляется после выполнения :!
команды.
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
Совет Райана, как правило, хорош, однако, если вы выполните шаг 3, не перемещайте временный файл; у него будут неправильные права собственности и разрешения. Вместо этого sudoedit
правильный файл и прочтите содержимое (используя :r
или подобное) временного файла.
Если вы :w!
выполните шаг 2, используйте для принудительной записи файла.
Быстрый гугл, кажется, дает такой совет:
- Не пытайтесь редактировать, если он предназначен только для чтения.
- Возможно, вы сможете изменить права доступа к файлу. (Позволит ли это вам сэкономить, зависит от экспериментов.)
- Если вы все равно редактировали, сохраните его во временный файл, а затем переместите его.
Быстрый прием, который вы можете рассмотреть, - это выполнить chmod для файла, который вы редактируете, сохранить с помощью vim, а затем вернуть chmod к исходному файлу.
ls -l test.file (to see the permissions of the file)
chmod 777 test.file
[This is where you save in vim]
chmod xxx test.file (restore the permissions you found in the first step)
Конечно, я не рекомендую этот подход в системе, где вы беспокоитесь о безопасности, так как в течение нескольких секунд любой может прочитать / изменить файл без вашего ведома.
Когда вы переходите в режим вставки файла, вам необходим доступ sudo для редактирования, вы получаете сообщение о состоянии
-- INSERT -- W10: Warning: Changing a readonly file
Если я пропущу это, как правило, я пропущу
:w ~/edited_blah.tmp
:q
..тогда..
sudo "cat edited_blah.tmp > /etc/blah"
..или..
sudo mv edited_blah.tmp /etc/blah
Вероятно, есть менее окольный способ сделать это, но он работает.
Вот еще один, появившийся после ответа на этот вопрос, плагин под названием SudoEdit, который предоставляет функции SudoRead и SudoWrite, которые по умолчанию будут пытаться сначала использовать sudo и su, если это не удается: http://www.vim.org/scripts/ script.php? script_id = 2709