Wielu z was prawdopodobnie widziało polecenie, które pozwala pisać na pliku, który wymaga uprawnień roota, nawet jeśli zapomniałeś otworzyć vima za pomocą sudo:
:w !sudo tee %
Chodzi o to, że nie rozumiem, co dokładnie się tutaj dzieje.
Już to wymyśliłem:
w
jest po to
*: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.
!sudo tee
Część połączeń tee
z uprawnieniami administratora.
Aby wszystko miało sens, %
powinna wypisać nazwę pliku (jako parametr dla tee
), ale nie mogę znaleźć referencji w pomocy dla tego zachowania.
tl; dr Czy ktoś mógłby mi pomóc w rozwikłaniu tego polecenia?
:w !sudo cat > %
Nie działałby tak dobrze i nie zanieczyszczałby standardowego wyjścia?sudo
ma zastosowanie docat
, ale nie do>
, więc nie jest dozwolone. Możesz spróbować uruchomić całe polecenie w podpowłoce sudo, na przykład:w !sudo sh -c "cat % > yams.txt"
, ale to też nie zadziała, ponieważ w podpowłoce%
jest zero; wyczyścisz zawartość swojego pliku.:w !sudo sh -c "cat >%"
faktycznie działa tak samo dobrze,sudo tee %
ponieważ Vim zastępuje nazwę pliku,%
zanim dotrze do podpowłoki. Jednak żadne z nich nie działa, jeśli nazwa pliku zawiera spacje; musisz to zrobić:w !sudo sh -c "cat >'%'"
lub:w !sudo tee "%"
to naprawić.Odpowiedzi:
W
:w !sudo tee %
...%
oznacza „bieżący plik”Jak wskazał eugene y ,
%
rzeczywiście oznacza „bieżącą nazwę pliku”, która jest przekazywana, abytee
wiedział, który plik należy zastąpić.(W poleceniach podmiany, to nieco inaczej, jak
:help :%
pokazy, toequal to 1,$ (the entire file)
(dzięki @Orafu za wskazanie, że to nie ocenia do nazwy pliku) Np.:%s/foo/bar
Środki „ w bieżącym pliku , wymień wystąpieniafoo
zbar
.” Jeśli kulminacyjnym trochę tekstu przed wpisaniem:s
, zobaczysz, że podświetlone linie zajmują miejsce%
jako zakres podstawiania).:w
nie aktualizuje twojego plikuJedną z niejasnych części tej sztuczki jest to, że możesz
:w
modyfikować plik, ale tak nie jest. Jeśli otworzyłeś i zmodyfikowałeśfile1.txt
, a następnie uruchomiłeś:w file2.txt
, byłoby to „zapisz jako”;file1.txt
nie zostanie zmodyfikowany, ale bieżąca zawartość bufora zostanie wysłana dofile2.txt
.Zamiast tego
file2.txt
możesz zastąpić polecenie powłoki, aby otrzymać zawartość bufora . Na przykład:w !cat
wyświetli tylko zawartość.Jeśli Vim nie był uruchamiany z dostępem sudo,
:w
nie może zmodyfikować chronionego pliku, ale jeśli przekazuje zawartość bufora do powłoki, polecenie w powłoce można uruchomić za pomocą sudo . W tym przypadku korzystamytee
.Zrozumienie tee
Co do tego
tee
, wyobraź sobietee
polecenie jako potok w kształcie litery T w normalnej sytuacji, w której wykonywany jest bash: kieruje wyjście do określonych plików, a także wysyła je do standardowego wyjścia , które może zostać przechwycone przez następne polecenie potoku.Na przykład
ps -ax | tee processes.txt | grep 'foo'
lista procesów zostanie zapisana w pliku tekstowym i przekazana dalejgrep
.(Schemat utworzony za pomocą Asciiflow .)
Zobacz
tee
stronę podręcznika, aby uzyskać więcej informacji.Tee jako hack
W sytuacji opisanej w pytaniu używanie
tee
to hack, 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 ignorujemy standardowe wyjście . W tym przypadku nie musimy przekazywać niczego do innego polecenia potokowego; używamy po prostutee
jako alternatywnego sposobu zapisu pliku, abyśmy mogli go wywołaćsudo
.Ułatwienie tej sztuczki
Możesz dodać to do swojego,
.vimrc
aby ta sztuczka była łatwa w użyciu: po prostu wpisz:w!!
.> /dev/null
Część wyraźnie odrzuca standardowe wyjście, ponieważ, jak powiedziałem, nie musimy przekazać cokolwiek innego polecenia rurami.źródło
tee
jego zdolność do zapisywania standardowego wejścia do pliku. Dziwię się, że nie ma programu, którego zadaniem jest to zrobić (znalazłem program, o którym nigdy nie słyszałem, że się nazywasponge
) Myślę, że typowe „zapisz strumień do pliku” jest wykonywane przez wbudowaną powłokę. Czy Vim!{cmd}
nie rozwidla muszli (cmd
zamiast tego rozwidla )? Być może czymś bardziej oczywistym byłoby użycie jakiegoś działającego wariantush -c ">"
zamiasttee
.sponge
jest częściąmoreutils
pakietu w prawie każdej dystrybucji oprócz dystrybucji opartych na Debianie.moreutils
ma całkiem niezłe narzędzia, które są na równi z bardziej popularnymi narzędziami, takimi jakxargs
itee
.cat
działa jako root, a dane wyjściowe są przekierowywane przez powłokę, która nie działa jako root. To jest tak samo jakecho hi > /read/only/file
.W wykonanym wierszu poleceń
%
oznacza bieżącą nazwę pliku . Jest to udokumentowane w:help cmdline-special
:Jak już się dowiedziałeś,
:w !cmd
potokuje zawartość bieżącego bufora do innego polecenia. Cotee
to jest kopiowanie standardowego wejścia do jednego lub więcej plików, a także na standardowe wyjście. Dlatego:w !sudo tee % > /dev/null
skutecznie zapisuje zawartość bieżącego bufora do bieżącego pliku , będąc rootem . Innym poleceniem, które można w tym celu zastosować, jestdd
:Jako skrót możesz dodać to mapowanie do
.vimrc
:Za pomocą powyższego możesz wpisać,
:w!!<Enter>
aby zapisać plik jako root.źródło
:help _%
wyświetla to, co wpisałeś, ale:help %
wyświetla klucz dopasowywania nawiasów. Nie pomyślałbym o wypróbowaniu prefiksu podkreślenia, czy to jakiś wzór w dokumentacji vima? Czy są jakieś inne „specjalne” rzeczy do wypróbowania podczas szukania pomocy?help
polecenie przeskakuje do znacznika. Możesz zobaczyć dostępne tagi za pomocą:h help-tags
. Możesz także użyć uzupełniania wiersza poleceń, aby zobaczyć pasujące tagi::h cmdline<Ctrl-D>
(lub:h cmdline<Tab>
jeśli odpowiednio ustawiszwildmode
)cmap w!! w !sudo tee % > /dev/null
w moim pliku .vimrc, aby to zadziałało. Czy%
zgubił się w powyższej odpowiedzi? (Nie ma tutaj eksperta vim.)sudo tee > /dev/null /path/to/current/file
że tak naprawdę nie ma to sensu. (Zamierzam to edytować)Działa to również dobrze:
Jest to inspirowane komentarzem @Nathana Longa.
UWAGA :
"
należy użyć zamiast tego,'
ponieważ chcemy%
rozszerzyć przed przejściem do powłoki.źródło
tee
je,/usr/bin/tee
aby zapobiec atakom modyfikującym PATH.:w
- Napisz plik.!sudo
- Wywołaj polecenie sudo powłoki.tee
- Dane wyjściowe polecenia write (vim: w) przekierowano za pomocą tee. % To nic innego jak bieżąca nazwa pliku, tj. /Etc/apache2/conf.d/mediawiki.conf. Innymi słowy, polecenie tee jest uruchamiane jako root i pobiera standardowe dane wejściowe i zapisuje je w pliku reprezentowanym przez%. Spowoduje to jednak ponowne załadowanie pliku (naciśnij L, aby załadować zmiany w samym vimie):link do samouczka
źródło
Zaakceptowana odpowiedź obejmuje to wszystko, dlatego podam kolejny przykład skrótu , którego używam, do zapisu.
Dodaj go do swojego
etc/vim/vimrc
(lub~/.vimrc
):cnoremap w!! execute 'silent! write !sudo tee % >/dev/null' <bar> edit!
Gdzie:
cnoremap
: mówi vimowi, że następujący skrót ma zostać skojarzony z linią poleceń.w!!
: sam skrót.execute '...'
: polecenie, które wykonuje następujący ciąg.silent!
: uruchom to po cichuwrite !sudo tee % >/dev/null
: pytanie OP, dodano przekierowanie wiadomości,NULL
aby wykonać czyste polecenie<bar> edit!
: ta sztuczka jest wisienką na torcie: wywołuje takżeedit
polecenie przeładowania bufora, a następnie uniknięcia komunikatów takich jak bufor się zmienił .<bar>
jest jak napisać symbol potoku, aby oddzielić tutaj dwa polecenia.Mam nadzieję, że to pomoże. Zobacz także inne problemy:
źródło
Chciałbym zasugerować inne podejście do „Oups, o których zapomniałem pisać
sudo
podczas otwierania pliku” :Zamiast odbierać
permission denied
i:w!!
muszę pisać , bardziej elegancko jest miećvim
polecenie warunkowe, które działa,sudo vim
jeśli właścicielem pliku jestroot
.Jest to równie łatwe do wdrożenia (mogą być nawet bardziej eleganckie implementacje, oczywiście nie jestem bash-guru):
I działa naprawdę dobrze.
Jest to bardziej
bash
skoncentrowane podejście niżvim
więc nie wszystkim może się to podobać.Oczywiście:
root
ale wymagasudo
, ale funkcję można edytować i tak)vim
do odczytu pliku (jeśli o mnie chodzi, używamtail
lubcat
do małych plików)Uważam jednak, że zapewnia to znacznie lepszą obsługę programistów , o czym IMHO często zapomina podczas korzystania
bash
. :-)źródło
root
pytane jest hasło.DLA NEOVIMA
Z powodu problemów z rozmowami interaktywnymi ( https://github.com/neovim/neovim/issues/1716 ) używam tego dla neovim, w oparciu o odpowiedź dr Beco:
Otworzy się okno dialogowe z
ssh-askpass
pytaniem o hasło sudo.źródło