Jak działa trick vim "write with sudo"?

Wielu z was prawdopodobnie widziało polecenie, które pozwala pisać na pliku, który wymaga uprawnień roota, nawet gdy zapomnieliście otworzyć Vima za pomocą sudo:

:w !sudo tee %
Rzecz w tym, że nie rozumiem, co się tu dzieje.

Już to wymyśliłem: w jest do tego

                                                        *: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 |:!|.

Więc przekazuje wszystkie linie jako standardowe wejście.

Część !sudo tee wywołuje tee z uprawnieniami administratora.

Aby wszystko miało sens, % powinno filename (jako parametr dla tee), ale nie mogę znaleźć referencji w pomocy dla tego zachowania.

Tl; dr mógłby mi ktoś pomóc rozpracować to polecenie?

 1168
Author: Yamaneko, 2010-04-08

6 answers

W :w !sudo tee %...

% oznacza "bieżący plik"

Jako eugene y wskazał, % rzeczywiście oznacza "bieżącą nazwę pliku". Innym zastosowaniem tego w Vimie jest zastępowanie poleceń. Na przykład :%s/foo/bar oznacza " w bieżącym pliku zastąp wystąpienia foo na bar."Jeśli podświetlisz jakiś tekst przed wpisaniem :s, zobaczysz, że podświetlone linie zastąpią % jako zakres podstawienia.

:w nie aktualizuje Twój plik

Jedną z mylących części tej sztuczki jest to, że możesz myśleć, że :w modyfikuje Twój plik, ale tak nie jest. jeśli otworzysz i zmodyfikujesz file1.txt, a następnie uruchomisz :w file2.txt, będzie to "zapisz jako"; file1.txt nie zostanie zmodyfikowany, ale bieżąca zawartość bufora zostanie wysłana do file2.txt.

Zamiast file2.txt, Możesz zastąpić polecenie powłoki, aby otrzymać zawartość bufora . Na przykład :w !cat wyświetli tylko zawartość.

If Vim wasn ' t run with sudo access, jego :w nie może modyfikować chronionego pliku, ale jeśli przekazuje zawartość bufora do powłoki, komenda w powłoce może być uruchomiona z sudo. W tym przypadku używamy tee.

Understanding tee

Jeśli chodzi o tee, wyobraź sobie komendę tee jako rurę w kształcie litery T w normalnej sytuacji rurociągu bash: kieruje ona wyjście do określonych plików, a wysyła je również do standardowego wyjścia, które może być przechwycone przez następne polecenie piped.

Dla przykład: w ps -ax | tee processes.txt | grep 'foo' lista procesów zostanie zapisana do pliku tekstowego , a zostanie przekazana do grep.

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

(Diagram utworzony za pomocą Asciiflow.)

Zobacz tee Strona man aby uzyskać więcej informacji.

Tee jako hack

W sytuacji, którą opisuje twoje pytanie, używanie tee jest włamaniem, ponieważ ignorujemy połowę tego, co robi. sudo tee zapisuje do naszego Pliku, a także wysyła zawartość bufora na standardowe wyjście, ale my ignoruj standardowe wyjście . W tym przypadku nie musimy przekazywać niczego do innego polecenia piped; używamy tylko tee jako alternatywnego sposobu zapisu pliku i tak, że możemy go wywołać za pomocą sudo.

Making this trick easy

Możesz dodać to do swojego .vimrc, aby ta sztuczka była łatwa w użyciu: po prostu wpisz :w!!.

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

Część > /dev/null jawnie odrzuca standardowe wyjście, ponieważ, jak powiedziałem, nie musimy niczego przekazywać do innego rurociągu dowództwo.

 1308
Author: Nathan Long,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-06 15:43:51

W wierszu poleceń % oznacza bieżącą nazwę pliku. Jest to udokumentowane w :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.

Jak już się dowiedziałeś, :w !cmd przekazuje zawartość bieżącego bufora do innej komendy. Co?tee does kopiuje standardowe wejście do jednego lub więcej plików, a także do standardowego wyjścia. Dlatego :w !sudo tee % > /dev/null efektywnie zapisuje zawartość bieżącego bufora do bieżącego pliku będąc rootem. Innym poleceniem, które może być używany do tego jest dd:

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

Jako skrót możesz dodać to mapowanie do swojego .vimrc:

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

Z powyższego możesz wpisać :w!!<Enter>, aby zapisać plik jako root.

 89
Author: Eugene Yarmash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-24 23:02:25

To również działa dobrze:

:w !sudo sh -c "cat > %"
To jest inspirowane komentarzem @ Nathan Long.

NOTICE :

" musi być użyte zamiast ', ponieważ chcemy, aby % zostało rozszerzone przed przekazaniem do powłoki.

 18
Author: feihu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-29 08:08:07

:w - Napisz plik.

!sudo - wywołaj polecenie Shell sudo.

tee - wyjście polecenia write (vim :w) Przekierowano za pomocą tee. W tym celu prosimy o zapoznanie się z naszą polityką prywatności.d / mediawiki.conf. Innymi słowy polecenie tee jest uruchamiane jako root i pobiera standardowe wejście i zapisuje je do pliku reprezentowanego przez %. Jednak spowoduje to ponowne wczytanie pliku (naciśnij L, aby załadować zmiany w samym Vimie): {]}

Tutorial link

 16
Author: kev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-04 06:02:49

Zaakceptowana odpowiedź obejmuje wszystko, więc podam kolejny przykład skrótu , którego używam, dla przypomnienia.

Dodaj go do swojego etc/vim/vimrc (LUB ~/.vimrc):

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

Gdzie:

  • cnoremap: informuje vim , że następujący Skrót ma być powiązany z wierszem poleceń.
  • w!!: sam skrót.
  • execute '...': polecenie wykonujące następujący ciąg znaków.
  • silent!: uruchom go po cichu
  • write !sudo tee % >/dev/null: pytanie OP, dodano przekierowanie Wiadomości do NULL, aby wykonać czyste polecenie
  • <bar> edit!: ta sztuczka jest wisienką na torcie: wywołuje również edit polecenie, aby przeładować bufor, a następnie uniknąć wiadomości, takich jak bufor zmienił się . <bar> jest jak napisać symbol pipe aby oddzielić dwa polecenia tutaj.
Mam nadzieję, że to pomoże. Zobacz także inne problemy:
 3
Author: Dr Beco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-13 07:12:59

Chciałbym zaproponować inne podejście do problemu "Oups zapomniałem napisać sudo podczas otwierania pliku":

Zamiast otrzymywania permission denied i konieczności wpisywania :w!!, bardziej eleganckie jest posiadanie warunkowego vim polecenia, które wykonuje sudo vim, jeśli właścicielem pliku jest root.

To jest tak łatwe do zaimplementowania (mogą być nawet bardziej eleganckie implementacje, wyraźnie nie jestem bash-guru): {]}
function vim(){
  OWNER=$(stat -c '%U' $1)
  if [[ "$OWNER" == "root" ]]; then
    sudo /usr/bin/vim $*;
  else
    /usr/bin/vim $*;
  fi
}

I działa naprawdę dobrze.

To jest bardziej bash - podejście skoncentrowane niż vim - takie, aby nie każdemu się to spodobało.

Oczywiście:

  • istnieją przypadki użycia, w których nie powiedzie się (gdy właściciel pliku nie jest root, ale wymaga sudo, ale funkcja może być edytowana)
  • Nie ma sensu używać vim do odczytu-tylko plik (jeśli O mnie chodzi, używam tail lub cat do małych plików)

Ale uważam, że przynosi to znacznie lepsze dev user experience , czyli coś o tym IMHO się zapomina przy używaniu bash. :-)

 1
Author: Augustin Riedinger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-28 18:21:56