Как работает трюк vim "писать с sudo"?

многие из вас, вероятно, видели команду, которая позволяет писать на файл, который нуждается в разрешении root, даже если вы забыли открыть vim с sudo:

:w !sudo tee %

дело в том, что я не понимаю, что именно здесь происходит.

Я уже понял это: w для этого

                                                        *:w_c* *:write_c*
:[range]w[rite] [++opt] !{cmd}
                        Execute {cmd} with [range] lines as standard input
                        (note the space in front of the '!').  {cmd} is
                        executed like with ":!{cmd}", any '!' is replaced with
                        the previous command |:!|.

таким образом, он передает все строки в качестве стандартного ввода.

на !sudo tee часть звонки tee С правами администратора.

для всех чтобы иметь смысл,% выводит имя файла (в качестве параметра tee), но я не могу найти ссылки на помощь такого поведения.

tl; dr может кто-нибудь помочь мне разобрать эту команду?

6 ответов


на :w !sudo tee %...

% означает "текущий файл"

As Евгений Игоревич указал, % действительно означает "текущее имя файла". Другое использование для этого в Vim-в командах подстановки. Например, :%s/foo/bar значит "в текущем файле заменить вхождения foo С bar."Если вы выделите текст перед вводом :s, вы увидите, что выделенные строки занимают место % как ваше диапазон замещения.

:w не обновляет файл

одна запутанная часть этого трюка заключается в том, что вы можете подумать :w изменяет ваш файл, но это не так. Если вы открыли и изменили file1.txt, затем побежал :w file2.txt, это было бы "сохранить как";file1.txt не будет изменен, но текущее содержимое буфера будет отправлено file2.txt.

вместо file2.txt вы можете замените команду оболочки для получения буфера содержание. Например, :w !cat будет просто отображать содержание.

если Vim не был запущен с доступом sudo, его :w не удается изменить защищенный файл, но если он передает содержимое буфера в оболочку, команда в оболочке can работать с sudo. В этом случае, мы используем tee.

понимание tee

как tee, картина tee команда как Т-образная труба в нормальной ситуации трубопровода Баш: он направляет вывод в указанный файл(Ы) и также отправляет его на стандартный вывод, который может быть захвачен следующей командой piped.

например,ps -ax | tee processes.txt | grep 'foo', список процессов будет записан в текстовый файл и до grep.

     +-----------+    tee     +------------+
     |           |  --------  |            |
     | ps -ax    |  --------  | grep 'foo' |
     |           |     ||     |            |
     +-----------+     ||     +------------+
                       ||   
               +---------------+
               |               |
               | processes.txt |
               |               |
               +---------------+

(диаграмма создана с помощью Asciiflow.)

посмотреть tee man page для получения дополнительной информации.

тройник как hack

в ситуации, которую описывает ваш вопрос,используя tee это хак, потому что мы игнорируем половину того, что он делает. sudo tee запись в наш файл и отправляет содержимое буфера на стандартный вывод, но мы игнорируем стандартный вывод. В этом случае нам не нужно ничего передавать другой команде piped; мы просто используем tee как альтернативный способ записи в файл и так, что мы можем назвать его sudo.

сделать это трюк легкий

вы можете добавить это в ваш .vimrc чтобы сделать этот трюк легкий в использовании: просто введите :w!!.

" Allow saving of files as sudo when I forgot to start vim using sudo.
cmap w!! w !sudo tee > /dev/null %

на > /dev/null часть явно выбрасывает стандартный вывод, так как, как я сказал, нам не нужно ничего передавать другой команде piped.


в выполненной командной строке % стоит нынешнее имя файла. Это задокументировано в :help cmdline-special:

In Ex commands, at places where a file name can be used, the following
characters have a special meaning.
        %       Is replaced with the current file name.

как вы уже выяснили, :w !cmd передает содержимое текущего буфера другой команде. Что?!--18-->tee does копирует стандартный ввод в один или несколько файлов, а также в стандартный вывод. Следовательно,:w !sudo tee % > /dev/null эффективно записывает содержимое буфера в текущий файл будучи root. Другая команда, которая может быть использована для этого, -dd:

:w !sudo dd of=% > /dev/null

в качестве ярлыка вы можете добавить это сопоставление в свой .vimrc:

" Force saving files that require root permission 
cnoremap w!! w !sudo tee > /dev/null %

с вышеизложенным вы можете ввести :w!!<Enter> сохранить файл как root.


Это также работает хорошо:

:w !sudo sh -c "cat > %"

это вдохновлено комментарием @Nathan Long.

обратите внимание:

" должен использоваться вместо ' потому что мы хотим % будет расширен до раковины.


:w - записать файл.

!sudo - вызовите команду shell sudo.

tee - вывод команды write (vim :w) перенаправляется с помощью tee. % - Это не что иное, как текущее имя файла, т. е. /etc/apache2/conf.д/медиавики.conf. Другими словами, команда tee запускается как root и принимает стандартный ввод и записывает его в файл, представленный %. Тем не менее, это предложит перезагрузить файл снова (нажмите L, чтобы загрузить изменения в самом vim):

учебник ссылка


принятый ответ охватывает все это, поэтому я просто приведу еще один пример ярлык это я использую для записи.

добавить его в свой etc/vim/vimrc (или ~/.vimrc):

  • cnoremap w!! execute 'silent! write !sudo tee % >/dev/null' <bar> edit!

где:

  • cnoremap: говорит vim что следующий ярлык должен быть связан в командной строке.
  • w!!: сам ярлык.
  • execute '...': команда которые выполняют следующую строку.
  • silent!: запустить его молча
  • write !sudo tee % >/dev/null: вопрос OP, добавлено перенаправление сообщений на NULL сделать "чистую" команду
  • <bar> edit!: этот трюк является вишней торта: он также называет edit команда для перезагрузки буфера, а затем избежать сообщений, таких как буфер изменился. <bar> как писать труба символ для разделения двух команд здесь.

надеюсь, что это помогает. См. также для других проблем:


я хотел бы предложить другой подход к "Ой, я забыл написать sudo при открытии моего файла" вопрос:

вместо permission denied, и имея типа :w!!, Я считаю более элегантным иметь условное