vim sudo




Как работает трюк vim «write with sudo»? (4)

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

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


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


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

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

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

УВЕДОМЛЕНИЕ :

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


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

Вместо того, чтобы получать 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 подход, чем vim -one, поэтому не всем это может понравиться.

Конечно:

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

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





sudo