Vim “sudo ile yazma” hilesi nasıl çalışır?


1410

Birçoğunuz vudo'yu sudo ile açmayı unuttuğunuzda bile, root iznine ihtiyaç duyan bir dosyaya yazmanıza izin veren komutu muhtemelen gördünüz:

:w !sudo tee %

Mesele şu ki, tam olarak burada olanları anlamıyorum.

Bunu zaten anladım: wbunun için

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

böylece tüm satırları standart girdi olarak geçirir.

!sudo teeParçası çağıran teeyönetici ayrıcalıklarıyla.

Herkes için mantıklı, %dosya adı çıktı (için bir parametre olarak tee), ancak bu davranış için yardım başvurular bulamıyorum.

tl; dr Birisi bu komutu incelememe yardım edebilir mi?


5
@Nathan: :w !sudo cat > %Standart çıktıyı da kirletmez, işe yaramaz mı?
Bjarke Freund-Hansen

51
@bjarkef - hayır, bu işe yaramıyor. Bu durumda, sudouygulanır cat, ancak uygulanmaz >, bu nedenle izin verilmez. Tüm komutu bir sudo alt kabuğunda çalıştırmayı deneyebilirsiniz :w !sudo sh -c "cat % > yams.txt", ancak bu da işe yaramaz, çünkü alt kabukta %nil; dosyanızın içeriğini boşaltırsınız.
Nathan Long

3
Bu komutu yazdıktan sonra bir uyarı mesajı görünebileceğini eklemek istiyorum. Eğer öyleyse, L tuşuna basın. Ardından, enter tuşuna basmanız istenecektir. Yapın ve sonunda dosyanız kaydedilecek.
pablofiumara

9
@NathanLong @knittl: :w !sudo sh -c "cat >%"aslında sudo tee %Vim subshell'e ulaşmadan %önce dosya adını değiştirir . Ancak, dosya adında boşluklar varsa ikisi de çalışmaz; bunu yapmak :w !sudo sh -c "cat >'%'"ya :w !sudo tee "%"da düzeltmek zorundasınız .
Han Seul-Oh

1
Kullanarak kaydedin: W ve dosyayı yeniden yükleyin: komut W: execute ': silent w! Sudo tee%> / dev / null' | :Düzenle!
Diego Roberto Dos Santos

Yanıtlar:


1610

İçinde :w !sudo tee %...

% "geçerli dosya" anlamına gelir

As Eugene y işaret , %aslında geçirilir "geçerli bir dosya adı", demek teeo üzerine yazmak hangi dosya bilmesi.

(İkame komutları, bu biraz farklı; olarak :help :%gösterdiği, bu kadar equal to 1,$ (the entire file)bu) dosya adına değerlendirmek etmediğini işaret için @Orafu (teşekkür Örneğin,. :%s/foo/barVasıtaları " cari dosyada , tekrarlarını değiştirmek fooile bar." Eğer vurgulamak Eğer yazmadan önce bazı metinlerde :s, vurgulanan satırların %ikame aralığınızın yerini aldığını görürsünüz .)

:w dosyanızı güncellemiyor

Bu hilenin kafa karıştırıcı bir parçası, :wdosyanızı değiştirdiğinizi düşünebilirsiniz , ancak değil. Açıp değiştirdiyseniz file1.txt, koştuysanız :w file2.txt, "farklı kaydet" olur; file1.txtdeğiştirilmez, ancak geçerli arabellek içeriği adresine gönderilir file2.txt.

Yerine file2.txtyapabilirsiniz tampon içeriğini almak için bir kabuk komutu yerine . Örneğin, :w !catsadece içeriği görüntüler.

Vim Sudo Erişimi çalışmaz ise, onun :wkorunmuş bir dosyasını değiştirmez, ancak kabuğa tamponu içeriğini geçerse, kabuk içinde bir komut olabilir Sudo ile çalıştırılabilir . Bu durumda kullanıyoruz tee.

Tee'yi anlama

İçin olduğu gibi tee, resim teenormal darbe boru durumda, bir T-şekilli boru olarak komut: belirtilen dosya (lar) çıkışı yönlendirir ve , aynı zamanda, standart çıkışa gönderir sonraki borulu komutu tarafından yakalanabilir.

Örneğin, içinde ps -ax | tee processes.txt | grep 'foo', işlemlerin listesi bir metin dosyasına yazılır ve adresine iletilir grep.

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

(Diyagram Asciiflow ile oluşturulmuştur .)

Daha fazla bilgi için teekılavuz sayfasına bakınız .

Bir kesmek gibi tee

Sorunuzun açıkladığı durumda, kullanmak teebir hack'tir çünkü yaptığımızın yarısını yok sayıyoruz . sudo teedosyamıza yazar ve arabellek içeriğini standart çıktıya gönderir, ancak standart çıktıyı yok sayarız . Bu durumda başka bir borulu komuta hiçbir şey iletmemiz gerekmiyor; sadece teebir dosya yazmanın alternatif bir yolu olarak kullanıyoruz ve böylece dosyayı çağırabiliriz sudo.

Bu numarayı kolaylaştırmak

.vimrcBu numarayı kullanımı kolay hale getirmek için bunu kendinize ekleyebilirsiniz : sadece yazın :w!!.

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

> /dev/nullBölüm açıkça dediğim gibi, başka bir borulu komuta şey geçmesi gerekmez, çünkü standart çıktıyı atıyor.


147
Özellikle sizin gösteriminiz gibi "w !!" "sudo !!" kullandıktan sonra hatırlaması çok kolay komut satırında.
Aidan Kane

11
Bu tee, bir dosyayı stdin yazma yeteneği için kullanır . İşi bunu yapmak olan bir program olmadığına şaşırdım (daha önce hiç duymadığım bir program buldum sponge, bunu yapan). Sanırım tipik bir "dosyaya bir akış yazma" yerleşik bir kabuk tarafından gerçekleştirilir. Vim !{cmd}bir mermiyi çatallamıyor mu (çatal cmdyerine)? Belki de daha belirgin olan bir şey, daha sh -c ">"ziyade bir çalışma varyantı kullanmak olacaktır tee.
Steven Lu

2
@Steven Lu: Debian merkezli dağıtımlar hariç hemen hemen her dağıtım paketinin bir spongeparçasıdır moreutils. ve moreutilsgibi daha yaygın araçlarla eşit olan oldukça güzel araçlara sahiptir . xargstee
İsviçre

10
Bu takma adı, vim'e değiştirilen dosya içeriğini otomatik olarak geçerli arabelleğe yüklemesini bildirmek için nasıl genişletilir? Bana soruyor, nasıl otomatikleştirilir?
Zlatko

10
@ user247077: Bu durumda, catkök olarak çalışır ve çıktı kök olarak çalışmayan kabuk tarafından yeniden yönlendirilir. İle aynı echo hi > /read/only/file.
WhyNotHugo

99

İdam komut doğrultusunda, %açılımı geçerli dosya adı . Bu belgelenmiştir :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.

Daha önce öğrendiğiniz gibi, :w !cmdgeçerli arabelleğin içeriğini başka bir komuta yönlendirir. Bu tee, standart girdiyi bir veya daha fazla dosyaya ve ayrıca standart çıktıya kopyalamaktır. Bu nedenle, :w !sudo tee % > /dev/nullgeçerli arabellek içeriğini etkin olarak geçerli dosyaya kök olarak yazar . Bunun için kullanılabilecek başka bir komut dd:

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

Kısayol olarak, bu eşlemeyi aşağıdakilere ekleyebilirsiniz .vimrc:

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

Yukarıdakilerle :w!!<Enter>dosyayı kök olarak kaydetmek için yazabilirsiniz .


1
İlginçtir, :help _%girdiğiniz şeyi getirir, ancak :help %küme ayracı eşleme anahtarını getirir. Alt çizgi önek denemek düşünmek olmaz, vim belgelerinde bir tür bir desen bu mu? Yardım ararken denemeniz gereken başka 'özel' şeyler var mı?
David Pope

2
@David: helpKomut bir etikete atlar. İle kullanılabilir etiketleri görebilirsiniz :h help-tags. Eşleşen etiketleri görmek için komut satırı tamamlamayı da kullanabilirsiniz: :h cmdline<Ctrl-D>(veya buna göre :h cmdline<Tab>ayarladıysanız wildmode)
Eugene Yarmash

1
cmap w!! w !sudo tee % > /dev/nullBu işi yapmak için .vimrc dosyamda kullanmak zorunda kaldım . Is %yukarıdaki yanıtında yanlış? (Burada vim uzmanı yok.)
dmmfll

@DMfll Evet, öyle. Cevaptaki komut sudo tee > /dev/null /path/to/current/filegerçekten anlamsızdır. (Bunu düzenleyecek)
jazzpi

1
@jazzpi: Yanılıyorsun. Kabuklar aslında komut satırında dosya yönlendirmesini nerede yaptığınızı umursamazlar.
Eugene Yarmash

19

Bu da işe yarar:

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

Bu, @Nathan Long'un yorumundan ilham alıyor.

FARKINA VARMAK :

"yerine kullanılmalıdır 'çünkü %kabuğa geçmeden önce genişletilmek istiyoruz .


11
Bu işe yarayabilirken, birden fazla programa (sh ve cat) sudo erişimi de verir. Diğer örnekler, PATH modifikasyon saldırılarını önlemek için teeile değiştirilerek daha güvenli olabilir /usr/bin/tee.
idbrii

18

:w - Bir dosya yazın.

!sudo - Arama kabuğu sudo komutu.

tee- Yazma (vim: w) komutunun çıktısı tee kullanılarak yeniden yönlendirildi. %, Geçerli dosya adından başka bir şey değildir, yani /etc/apache2/conf.d/mediawiki.conf. Başka bir deyişle tee komutu root olarak çalıştırılır ve standart girdi alır ve% ile temsil edilen bir dosyaya yazar. Ancak, bu dosyayı yeniden yüklemenizi ister (vim'deki değişiklikleri yüklemek için L tuşuna basın):

öğretici bağlantı


9

Kabul edilen cevap her şeyi kapsıyor, bu yüzden başka bir kısayol örneği vereceğim kayıt için kullandığım .

Bunu etc/vim/vimrc(veya ~/.vimrc) cihazınıza ekleyin :

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

Nerede:

  • cnoremap: vim söyler aşağıdaki kısayolun komut satırında ilişkilendirileceğini belirtir.
  • w!!: kısayolun kendisi.
  • execute '...': aşağıdaki dizeyi yürüten bir komut.
  • silent!: sessizce çalıştır
  • write !sudo tee % >/dev/null: OP sorusu, iletilere bir yönlendirme ekledi NULL temiz bir komut yapmak için
  • <bar> edit!: bu hile pastanın kiraz: aynı zamanda edittamponu yeniden yüklemek ve sonra tampon değişti gibi mesajları önlemek için komut çağırır . boru<bar> nasıl yazılırburada iki komutu ayırmak sembolünün .

Umarım yardımcı olur. Diğer sorunlar için de bakınız:


sessiz! Parola istemini devre dışı
Andy Ray

7

"Dosyamı açarken yazmayı unuttuğum Oups" a başka bir yaklaşım önermek istiyorumsudo sorununa :

A almak permission deniedve yazmak zorunda kalmak yerine, dosya sahibinin yaptığı :w!!koşullu bir vimkomuta sahip olmak daha zarif buluyorum .sudo vimroot

Bunu uygulamak o kadar kolay (daha zarif uygulamalar bile olabilir, açıkça bir bash-guru değilim):

function vim(){
  OWNER=$(stat -c '%U' $1)
  if [[ "$OWNER" == "root" ]]; then
    sudo /usr/bin/vim $*;
  else
    /usr/bin/vim $*;
  fi
}

Ve gerçekten iyi çalışıyor.

Bu bir bash-e göre daha merkezli bir yaklaşımdır, vimbu yüzden herkes bundan hoşlanmayabilir.

Elbette:

  • başarısız olacağı kullanım durumları vardır (dosya sahibi değil rootancak gerektirir sudo, ancak işlev yine de düzenlenebilir)
  • kullanırken bu mantıklı değil vimbir dosyayı salt okumak için (bildiğim kadarıyla endişeleniyorum olarak, kullandığım tailveya catküçük dosyalar için)

Ama bunun çok daha iyi bir dev kullanıcı deneyimi getirdiğini görüyorum , bu IMHO'nun kullanırken unutulmaya meyilli bir şey bash. :-)


5
Bunun çok daha az bağışlayıcı olduğunu unutmayın. Şahsen, hatalarımın çoğu aptalca hatalar. Bu yüzden hem aptal hem de sonuçsal olabilecek bir şey yaparken kafa kafaya gitmeyi tercih ederim. Bu elbette bir tercih meselesidir, ancak ayrıcalık yükselmesi vicdani bir eylem olarak görülmüştür. Ayrıca: Bunu sık sık ": w !!" sessizce otomatik sudo için yeterince rahatsız (ama sadece owner = root); mevcut iş akışınızı incelemek isteyebilirsiniz.
Payne

İlginç bir yorum olsa da, bilinçli olmalıdır çünkü dosya açıldığında rootşifre sorgulanırken.
Augustin Riedinger

Ah! Fark var. Sudo kullanıcısının "NOPASSWD" ayarlı olup olmadığına bağlıdır.
Payne

Sonra NOPASSWD sahip olduğu daha az affedici :) ... ne
Augustin Riedinger

4

NEOVIM İÇİN

Etkileşimli çağrılarla ilgili sorunlar nedeniyle ( https://github.com/neovim/neovim/issues/1716 ), bunu Dr Beco'nun cevabına dayanarak neovim için kullanıyorum:

cnoremap w!! execute 'silent! write !SUDO_ASKPASS=`which ssh-askpass` sudo tee % >/dev/null' <bar> edit!

Bu ssh-askpass, sudo şifresini soran bir iletişim kutusu açar .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.