Uzyskiwanie uprawnień roota do pliku w vi? [Zamknięte]

245

Często podczas edycji plików konfiguracyjnych otwieram jeden z vi, a potem, kiedy go zapisuję, zdaję sobie sprawę, że nie wpisałem

sudo vi filename

Czy jest jakiś sposób nadania vi sudo uprawnień do zapisania pliku? Wydaje mi się, że coś o tym pamiętam, gdy jakiś czas temu szukałem informacji na temat vi, ale teraz nie mogę tego znaleźć.

Paul Wicks
źródło
może po prostu zapisz kopię w swoim katalogu domowym i „sudo mv” później
paan

Odpowiedzi:

296

% zostaje zastąpiony bieżącą nazwą pliku, więc możesz użyć:

:w !sudo tee %

( vimwykryje, że plik został zmieniony i zapyta, czy chcesz go ponownie załadować. Powiedz tak, wybierając [L]raczej niż OK.)

Jako skrót możesz zdefiniować własne polecenie. Umieść w swoim .vimrc:

command W w !sudo tee % >/dev/null

Za pomocą powyższego możesz wpisać, :W<Enter>aby zapisać plik. Odkąd to napisałem, znalazłem lepszy sposób (moim zdaniem), aby to zrobić:

cmap w!! w !sudo tee >/dev/null %

W ten sposób możesz pisać, :w!!a zostanie ono rozwinięte do pełnego wiersza poleceń, pozostawiając kursor na końcu, dzięki czemu możesz zastąpić %własną nazwą pliku, jeśli chcesz.

beroe
źródło
5
Czy to działa w gvim? Uruchomienie polecenia powoduje, że Vim pyta o hasło, ale nie akceptuje danych wejściowych. W końcu sudo: 1 incorrect password attempt
limit
nie widziałbym powodu, dla którego gvim miałby zachowywać się inaczej ... czy jesteś pewien, że sudo samo w sobie działa poprawnie?
Jeśli potrzebujesz uprawnień roota, aby zapisać nowy plik, zamień% na nazwę (wraz ze ścieżką) nowego pliku.
gvkv,
Czasami musisz najpierw dodać użytkownika do pliku sudoer, wprowadzić użytkownika root i otworzyć /etc/sudoersplik, dodać your_username ALL=(ALL) ALLpod linią root ALL=(ALL) ALL, wyjść i zapisać.
najciekawsze
1
@coolesting: 1) istnieje około tysiąca innych rzeczy, które musisz zrobić… nie możemy ich wszystkich wymienić. 2) zawsze powinieneś używać visudo.
32

Zasadniczo nie można zmienić efektywnego identyfikatora użytkownika procesu vi, ale można to zrobić:

:w !sudo tee myfile
Mark Harrison
źródło
1
:w !sudo tee % >/dev/nulllub :w !sudo dd of=%unikaj echa zawartości pliku podczas zapisywania pliku.
jamessan,
Czy możesz wyjaśnić, jak to działa? Podniosłem wzrok teei zobaczyłem, że jest to polecenie potoku Unix, i !wstawia polecenie powłoki. Czy :wzapisywanie jest obecnie standardowe, przez co jest przesyłane tee?
Eric Hu
4
@Eric, zgadza się. polecenie „tee myfile” skopiuje standardowe wejście do mojego pliku. uruchomienie „sudo tee myfile” zrobi to samo, ale ponieważ proces tee jest własnością root, myfile będzie również własnością root. Po stronie vi „: w! Some wiersza poleceń” poprowadzi wszystkie linie do „some wiersza poleceń”.
Mark Harrison
16

Wspólne zastrzeżenia

Najczęstszą metodą obejścia problemu z plikiem tylko do odczytu jest otwarcie potoku do bieżącego pliku jako superużytkownik za pomocą implementacji sudo tee. Jednak wszystkie najpopularniejsze rozwiązania, które znalazłem w Internecie, mają kombinację kilku potencjalnych zastrzeżeń:

  • Cały plik zostanie zapisany w terminalu, a także plik. Może to być powolne w przypadku dużych plików, szczególnie w przypadku wolnych połączeń sieciowych.
  • Plik traci tryby i podobne atrybuty.
  • Ścieżki plików z nietypowymi znakami lub spacjami mogą nie być obsługiwane poprawnie.

Rozwiązania

Aby obejść wszystkie te problemy, możesz użyć następującego polecenia:

" On POSIX (Linux/Mac/BSD):
:silent execute 'write !sudo tee ' . shellescape(@%, 1) . ' >/dev/null'

" Depending on the implementation, you might need this on Windows:
:silent execute 'write !sudo tee ' . shellescape(@%, 1) . ' >NUL'

Można je z szacunkiem skrócić:

:sil exec 'w !sudo tee ' . shellescape(@%, 1) . ' >/dev/null'
:sil exec 'w !sudo tee ' . shellescape(@%, 1) . ' >NUL'

Wyjaśnienie

:rozpoczyna polecenie; musisz wpisać ten znak w trybie normalnym, aby rozpocząć wprowadzanie polecenia. Należy to pominąć w skryptach.

sil[ent]pomija dane wyjściowe polecenia. W takim przypadku chcemy zatrzymać Press any key to continuemonit podobny do polecenia, który pojawia się po uruchomieniu :!polecenia.

exec[ute]wykonuje ciąg jako polecenie. Nie możemy tak po prostu uruchomić, :writeponieważ nie przetworzy wymaganego wywołania funkcji.

!reprezentuje :!polecenie: jedyne polecenie, które :writeakceptuje. Zwykle :writeakceptuje ścieżkę do pliku, do którego należy zapisać. :!samodzielnie uruchamia polecenie w powłoce (na przykład przy użyciu bash -c). Za pomocą :writeuruchomi polecenie w powłoce, a następnie zapisze cały plik do stdin.

sudopowinno być oczywiste, ponieważ właśnie dlatego tu jesteś. Uruchom polecenie jako superużytkownik. W sieci jest mnóstwo informacji o tym, jak to działa.

teepotoki stdindo podanego pliku. :writenapisze do stdin, a następnie superużytkownik teeotrzyma zawartość pliku i zapisze plik. Nie utworzy nowego pliku - po prostu nadpisze zawartość - więc tryby plików i atrybuty zostaną zachowane.

shellescape()zmienia znaki specjalne w podanej ścieżce do pliku odpowiednio do bieżącej powłoki. Za pomocą tylko jednego parametru zwykle zawiera ścieżkę w cudzysłowie, jeśli to konieczne. Ponieważ wysyłamy do wiersza poleceń pełnej powłoki, będziemy chcieli przekazać wartość niezerową jako drugi argument, aby umożliwić odwrotne ukośniki innym znakom specjalnym, które w przeciwnym razie mogłyby wyzwolić powłokę.

@%odczytuje zawartość %rejestru, który zawiera nazwę pliku bieżącego bufora. Nie musi to być ścieżka bezwzględna, więc upewnij się, że nie zmieniłeś bieżącego katalogu. W niektórych rozwiązaniach pominięty zostanie symbol reklamowy. W zależności od lokalizacji %jest prawidłowym wyrażeniem i ma taki sam efekt jak odczyt %rejestru. Zagnieżdżony w innym wyrażeniu skrót jest jednak ogólnie niedozwolony: tak jak w tym przypadku.

>NULi >/dev/nullprzekieruj stdoutdo zerowego urządzenia platformy. Mimo że uciszyliśmy polecenie, nie chcemy, aby cały narzut związany z przesyłaniem potoków stdinwrócił do vima - najlepiej zrzucić go jak najwcześniej. NULjest zerowym urządzeniem w DOS, MS-DOS i Windows, a nie jest prawidłowym plikiem. Od Windows 8 przekierowania do NUL nie powodują zapisania pliku o nazwie NUL. Spróbuj utworzyć plik na pulpicie o nazwie NUL, z rozszerzeniem lub bez: nie będzie można tego zrobić. (Istnieje kilka innych nazw urządzeń w systemie Windows, które warto poznać).

~ / .vimrc

Zależny od platformy

Oczywiście nadal nie chcesz ich zapamiętywać i wpisywać za każdym razem. Znacznie łatwiej jest zamapować odpowiednie polecenie na prostsze polecenie użytkownika. Aby to zrobić w systemie POSIX, możesz dodać następujący wiersz do swojego ~/.vimrcpliku, tworząc go, jeśli jeszcze nie istnieje:

command W silent execute 'write !sudo tee ' . shellescape(@%, 1) . ' >/dev/null'

Umożliwi to wpisanie polecenia: W (z uwzględnieniem wielkości liter), aby zapisać bieżący plik z uprawnieniami superużytkownika - znacznie łatwiej.

Niezależny od platformy

Korzystam z niezależnego od platformy ~/.vimrcpliku, który synchronizuje się między komputerami, dlatego do mojego dołączyłem funkcję obsługi wielu platform. Oto ~/.vimrctylko odpowiednie ustawienia:

#!vim
" Use za (not a command; the keys) in normal mode to toggle a fold.
" META_COMMENT Modeline Definition: {{{1
" vim: ts=4 sw=4 sr sts=4 fdm=marker ff=unix fenc=utf-8
"   ts:     Actual tab character stops.
"   sw:     Indentation commands shift by this much.
"   sr:     Round existing indentation when using shift commands.
"   sts:    Virtual tab stops while using tab key.
"   fdm:    Folds are manually defined in file syntax.
"   ff:     Line endings should always be <NL> (line feed #09).
"   fenc:   Should always be UTF-8; #! must be first bytes, so no BOM.


" General Commands: User Ex commands. {{{1
    command W call WriteAsSuperUser(@%)         " Write file as super-user.


" Helper Functions: Used by user Ex commands. {{{1
    function GetNullDevice() " Gets the path to the null device. {{{2
        if filewritable('/dev/null')
            return '/dev/null'
        else
            return 'NUL'
        endif
    endfunction

    function WriteAsSuperUser(file) " Write buffer to a:file as the super user (on POSIX, root). {{{2
        exec '%write !sudo tee ' . shellescape(a:file, 1) . ' >' . GetNullDevice()
    endfunction


" }}}1
" EOF
Zenexer
źródło
Co się stanie, jeśli uruchomisz system Windows, tworząc plik do zapisu na świecie w C: \ dev \ null?
Paul Stelian
1
@PaulStelian Możliwe, ale mało prawdopodobne. Możesz z łatwością rozszerzyć ten kod, aby uwzględnić różne platformy i okoliczności. W rzeczywistości jest mało prawdopodobne, aby w Windows występowała sytuacja, która sudoistnieje, ale nie /dev/null, więc musisz być bardziej wyrafinowany, jeśli chcesz prawdziwej pomocy wieloplatformowej. To raczej wstęp - jedzenie do namysłu. :)
Zenexer,
11

Jeśli używasz Vima , dostępny jest skrypt o nazwie sudo.vim . Jeśli okaże się, że otworzyłeś plik, do którego odczytu potrzebujesz dostępu roota, wpisz

: e sudo:%
Vim zastępuje% nazwą bieżącego pliku i sudo:instruuje skrypt sudo.vim, aby przejął jego odczyt i zapis.

efemeryczny
źródło
4
Nie zalecałbym używania tego skryptu, ponieważ nie zachowuje on odpowiednich środków ostrożności przy unikaniu nazw plików.
jamessan,
7

Rada Ryana jest na ogół dobra, jednak jeśli wykonasz krok 3, nie przenoś pliku tymczasowego; będzie miał niewłaściwe prawa własności i uprawnienia. Zamiast sudoedittego poprawny plik i wczytaj zawartość (używając :rlub podobną) pliku tymczasowego.

Jeśli wykonasz krok 2, użyj, :w!aby wymusić zapisanie pliku.

Chris Jester-Young
źródło
3

Gdy przejdziesz do trybu wstawiania pliku, potrzebujesz edycji sudo, pojawi się komunikat o stanie

-- INSERT -- W10: Warning: Changing a readonly file

Jeśli mi tego brakuje, zazwyczaj tak jest

:w ~/edited_blah.tmp
:q

..następnie..

sudo "cat edited_blah.tmp > /etc/blah"

..lub..

sudo mv edited_blah.tmp /etc/blah

Prawdopodobnie jest to mniej okrężny sposób, ale działa.

dbr
źródło
cat $ tmp> $ target jest kreatywny, ale czy jest jakiś powód, aby nie tylko sudo mv pliku?
ojrac
Dobra uwaga .. Wystąpił także duży problem z sudo cat czymś> / etc / blah - który użyje sudo do przechwycenia pliku, a następnie zwykłego użytkownika do napisania do / etc / blah (co nie działa) .. Naprawiono to w odpowiedź i dodał swoją lepszą sugestię sudo mv ..
dbr
Sugestia mv nie zachowuje uprawnień.
Paul Stelian,
1

Szybkie Google wydaje się dawać tę radę:

  1. Nie próbuj edytować, jeśli jest tylko do odczytu.
  2. Możesz być w stanie zmienić uprawnienia do pliku. (To, czy pozwoli ci to zaoszczędzić, zależy od eksperymentów).
  3. Jeśli mimo to nadal edytowałeś, zapisz w pliku tymczasowym, a następnie przenieś go.

http://ubuntuforums.org/showthread.php?t=782136

Ryan Fox
źródło
1

Oto kolejna, która pojawiła się od czasu odpowiedzi na to pytanie, wtyczka o nazwie SudoEdit, która zapewnia funkcje SudoRead i SudoWrite, która domyślnie spróbuje użyć najpierw sudo i su, jeśli to się nie powiedzie: http://www.vim.org/scripts/ script.php? script_id = 2709

James Snyder
źródło
0

Mam to w moim ~ / .bashrc:

alias svim='sudo vim'

Teraz, gdy muszę edytować plik konfiguracyjny, po prostu otwieram go za pomocą svim.

pisswillis
źródło
2
sudoeditPolecenie powinno być korzystne, ponieważ nie wymaga on uruchomiony vim jako root.
jamessan
2
To wciąż nie powstrzymuje cię od wiązania vima zamiast svima, do czego wymyka się OP.
ScaryAardvark
3
-1, to po prostu mówi „pamiętaj, aby pisać sudo podczas otwierania pliku”, OP chce wiedzieć, w jaki sposób mogą uzyskać uprawnienia roota w vi.
Brad Koch
-2

Szybki hack, który możesz rozważyć, to wykonanie chmod na edytowanym pliku, zapisanie go za pomocą vima, a następnie chmod z powrotem do pierwotnego pliku.

ls -l test.file (to see the permissions of the file)
chmod 777 test.file
[This is where you save in vim]
chmod xxx test.file (restore the permissions you found in the first step)

Oczywiście nie polecam tego podejścia w systemie, w którym martwisz się o bezpieczeństwo, ponieważ przez kilka sekund każdy może odczytać / zmienić plik bez Twojej wiedzy.

num1
źródło