Как работает трюк vim "write with 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 Может ли кто-нибудь помочь мне проанализировать эту команду?

1047
08 апр. '10 в 17:36
источник поделиться
6 ответов

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

Как eugene y указал, % действительно означает "текущее имя файла". Другое использование для этого в 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 не может изменить защищенный файл, но если он передает содержимое буфера в оболочку, команда в оболочке может быть запущена с помощью sudo. В этом случае мы используем tee.

Понимание тройника

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

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

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

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

Подробнее см. tee справочная страница.

Тройник как хак

В ситуации, которую ваш вопрос описывает, с использованием tee является взломом, потому что мы игнорируем половину того, что он делает. sudo tee записывает в наш файл, а также отправляет содержимое буфера на стандартный вывод, но игнорирует стандартный вывод. В этом случае нам не нужно передавать что-либо другой команде; мы просто используем 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 часть явно выбрасывает стандартный вывод, так как, как я уже сказал, нам не нужно передавать что-либо другой команде.

1188
16 авг. '11 в 15:49
источник

Связанные вопросы


Похожие вопросы

В выполненной командной строке % обозначает текущее имя файла. Это описано в :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 связывает содержимое текущего буфера с другой командой. Что tee - это стандартный ввод текста в один или несколько файлов, а также стандартный вывод. Поэтому :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.

83
08 апр. '10 в 17:45
источник

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

!sudo - Вызывать команду оболочки sudo.

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

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

15
04 июня '11 в 9:02
источник

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

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

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

УВЕДОМЛЕНИЕ

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

15
29 июля '14 в 11:08
источник

Приведенное выше отображение отлично работает для меня, чтобы сохранить использование sudo и перезагрузить файл без нажатия дополнительных клавиш. (просто нажмите w)

map w :execute ':silent w !sudo tee % > /dev/null' <bar> :edit! <cr>
0
30 янв. '18 в 22:33
источник

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

Добавьте его в свой 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> заключается в том, как написать символ трубы для разделения двух команд здесь.

Надеюсь, это поможет. См. Также другие проблемы:

0
13 янв. '18 в 10:12
источник

Посмотрите другие вопросы по меткам или Задайте вопрос