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

+1293
08 апр. '10 в 14:36
источник поделиться
7 ответов

В :w !sudo tee %...

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

Как отметил Евгений У, % действительно означает "текущее имя файла". Другое использование для этого в 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' ps -ax | tee processes.txt | grep 'foo' 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 явно отбрасывает стандартный вывод, поскольку, как я уже сказал, нам не нужно ничего передавать другой переданной команде.

+1465
16 авг. '11 в 12: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.

+93
08 апр. '10 в 14:45
источник

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

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

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

УВЕДОМЛЕНИЕ

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

+18
29 июл. '14 в 8:08
источник

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

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

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

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

+16
04 июн. '11 в 6:02
источник

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

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

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

+6
13 янв. '18 в 7:12
источник

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

Вместо того, чтобы получить permission denied в permission denied, и необходимо набрать :w!! Я считаю более элегантным иметь условную команду vim которая делает sudo vim если владельцем файла является root.

Это так же просто реализовать (могут быть и более элегантные реализации, я явно не баш-гуру):

function vim(){
  OWNER=$(stat -c '%U' $1)
  if [[ "$OWNER" == "root" ]]; then
    sudo /usr/bin/vim $*;
  else
    /usr/bin/vim $*;
  fi
}

И это работает очень хорошо.

Это более подход bash -centered, чем vim -one, поэтому не всем это понравится.

Конечно:

  • есть случаи, когда это не удастся (когда владелец файла не является пользователем root но требует sudo, но функция может быть отредактирована в любом случае)
  • это не имеет смысла при использовании vim для чтения файла (насколько я понимаю, я использую tail или cat для небольших файлов)

Но я нахожу, что это дает гораздо лучший опыт для разработчиков, что IMHO, как правило, забывается при использовании bash. :-)

+4
28 февр. '18 в 18:21
источник

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

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

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