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?
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.
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.
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.
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): {]}
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 doNULL
, 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.
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
.
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 wymagasudo
, 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
. :-)
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