विम "सुडोल के साथ कैसे लिखता है" चाल काम करती है?


1410

आप में से कई लोगों ने संभवतः कमांड को देखा है जो आपको एक फाइल पर लिखने की अनुमति देता है, जिसे रूट अनुमति की आवश्यकता होती है, तब भी जब आप sudo के लिए vim खोलना भूल गए हों:

:w !sudo tee %

बात यह है कि मुझे यहां वह नहीं मिलता जो वास्तव में हो रहा है।

मैंने पहले ही यह समझ लिया है: wइसके लिए है

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

इसलिए यह मानक इनपुट के रूप में सभी लाइनों को पास करता है।

!sudo teeभाग कॉल teeव्यवस्थापक विशेषाधिकारों के साथ।

सभी को समझ में आने के लिए, %फ़ाइल नाम (एक पैरामीटर के लिए tee) के रूप में आउटपुट करना चाहिए , लेकिन मुझे इस व्यवहार के लिए सहायता पर संदर्भ नहीं मिल सकते हैं।

tl; डॉ। कोई मेरी मदद कर सकता है इस आदेश को विच्छेदित करने में?


5
@ नथन: :w !sudo cat > %मानक आउटपुट को प्रदूषित करने के साथ-साथ काम नहीं करेगा ?
बजरैक फ्रायंड-हैनसेन

51
@bjarkef - नहीं, यह काम नहीं करता है। उस मामले में, sudoपर लागू किया जाता है cat, लेकिन नहीं >, इसलिए इसकी अनुमति नहीं है। आप एक sudo सबशेल में पूरे कमांड को चलाने की कोशिश कर सकते हैं, जैसे :w !sudo sh -c "cat % > yams.txt", लेकिन यह सब या तो काम नहीं करेगा, क्योंकि सबशेल में, %nil है; आप अपनी फ़ाइल की सामग्री को खाली कर देंगे।
नाथन लॉन्ग

3
मैं केवल उस आदेश को टाइप करने के बाद जोड़ना चाहता हूं, एक चेतावनी संदेश दिखाई दे सकता है। यदि हां, तो L. तब, आपको एंटर प्रेस करने के लिए कहा जाएगा। करो और तुम अंत में अपनी फ़ाइल को बचा लिया होगा।
पेलोबोफियारा

9
@NathanLong @knittl: :w !sudo sh -c "cat >%"वास्तव में सिर्फ sudo tee %इसलिए काम करता है क्योंकि विम %कभी फ़ाइल को सब्सक्राइब करने से पहले उसके लिए फ़ाइल नाम को प्रतिस्थापित करता है । हालांकि, उनमें से कोई भी काम नहीं करता है यदि फ़ाइलनाम में रिक्त स्थान है; आपको उसे ठीक करना है :w !sudo sh -c "cat >'%'"या :w !sudo tee "%"करना है।
हान सियोल-ओह

1
सहेजें का उपयोग करें: W और फ़ाइल को पुनः लोड करें: कमांड W: 'निष्पादित करें: मौन w! Sudo tee%> / dev / null' | : संपादित करें!
डिएगो रॉबर्टो डॉस सैंटोस

जवाबों:


1610

में :w !sudo tee %...

% का अर्थ है "वर्तमान फ़ाइल"

जैसा कि यूजीन वाई ने बताया , %वास्तव में "वर्तमान फ़ाइल नाम" का मतलब है, जो कि इस तरह से पारित हो जाता teeहै कि यह जानता है कि कौन सी फ़ाइल को अधिलेखित करना है।

(प्रतिस्थापन आदेशों में, यह थोड़ा अलग है; जैसा कि :help :%दिखाता है, यह equal to 1,$ (the entire file)@Orafu के लिए धन्यवाद है कि यह इंगित करने के लिए कि यह फ़ाइल नाम का मूल्यांकन नहीं करता है)। उदाहरण के लिए, :%s/foo/bar" वर्तमान फ़ाइल में , का अर्थ है" के fooसाथ होने वाली घटनाओं को बदलें bar। टाइप करने से पहले कुछ पाठ :s, आप देखेंगे कि हाइलाइट की गई लाइनें %आपके प्रतिस्थापन रेंज के रूप में जगह लेती हैं ।)

:w अपनी फ़ाइल को अपडेट नहीं कर रहा है

इस ट्रिक का एक भ्रामक हिस्सा यह है कि आप सोच सकते हैं कि :wयह आपकी फ़ाइल को संशोधित कर रहा है, लेकिन ऐसा नहीं है। यदि आपने खोला और संशोधित किया file1.txt, तो भाग गया :w file2.txt, यह "के रूप में सहेजें" होगा; file1.txtसंशोधित नहीं किया जाएगा, लेकिन वर्तमान बफर सामग्री को भेजा जाएगा file2.txt

इसके बजाय file2.txt, आप बफर सामग्री प्राप्त करने के लिए शेल कमांड को स्थानापन्न कर सकते हैं । उदाहरण के लिए, :w !catकेवल सामग्री प्रदर्शित करेगा।

अगर विम को सुडो एक्सेस के साथ नहीं चलाया गया था :w, तो यह एक संरक्षित फ़ाइल को संशोधित नहीं कर सकता है, लेकिन यदि यह बफर सामग्री को शेल में पास करता है, तो शेल में एक कमांड को सूडो के साथ चलाया जा सकता है । इस मामले में, हम उपयोग करते हैं tee

टी को समझना

के रूप में tee, teeकमांड को टी-आकार के पाइप के रूप में एक सामान्य बैश पाइपिंग स्थिति में चित्रित करें : यह आउटपुट को निर्दिष्ट फ़ाइल (एस) में निर्देशित करता है और इसे मानक आउटपुट पर भी भेजता है , जिसे अगले पाइप्ड कमांड द्वारा कैप्चर किया जा सकता है।

उदाहरण के लिए, में ps -ax | tee processes.txt | grep 'foo', प्रक्रियाओं की सूची एक पाठ फ़ाइल को लिखी जाएगी और उसके साथ पारित की जाएगी grep

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

( Asciiflow के साथ बनाया आरेख )

अधिक जानकारी के लिए teeमैन पेज देखें ।

एक हैक के रूप में टी

जिस स्थिति में आपका प्रश्न वर्णित है, उसका उपयोग teeकरना हैक है क्योंकि हम जो करते हैं उसका आधा अनदेखा कर रहे हैंsudo teeहमारी फ़ाइल को लिखता है और मानक सामग्री को बफर सामग्री भी भेजता है, लेकिन हम मानक आउटपुट की उपेक्षा करते हैं । हमें इस मामले में किसी अन्य पाइप्ड कमांड को कुछ भी पास करने की आवश्यकता नहीं है; हम केवल teeएक फ़ाइल लिखने के वैकल्पिक तरीके के रूप में उपयोग कर रहे हैं और ताकि हम इसे कॉल कर सकें sudo

इस ट्रिक को आसान बनाना

.vimrcइस ट्रिक को आसान बनाने के लिए आप इसे अपने साथ जोड़ सकते हैं : बस टाइप करें :w!!

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

> /dev/nullभाग स्पष्ट रूप से मानक आउटपुट फेंक देता है, के बाद से, जैसा कि मैंने कहा, हम एक और पाइप आदेश के लिए कुछ भी पारित करने के लिए की जरूरत नहीं है।


147
विशेष रूप से अपने संकेतन "w !!" जो "sudo !! कमांड लाइन पर।
ऐदन केन

11
तो यह teeएक फ़ाइल में स्टड लिखने की अपनी क्षमता के लिए उपयोग करता है । मुझे आश्चर्य है कि ऐसा कोई कार्यक्रम नहीं है जिसका काम यह करना है (मुझे ऐसा प्रोग्राम मिला है spongeजिसके बारे में मैंने कभी नहीं सुना है जो ऐसा करता है)। मुझे लगता है कि ठेठ "एक फ़ाइल में एक स्ट्रीम लिखें" एक शेल में निर्मित द्वारा किया जाता है। क्या विम का !{cmd}एक खोल ( cmdइसके बजाय कांटा ) कांटा नहीं है ? शायद कुछ ऐसा है जो अधिक स्पष्ट है sh -c ">"बजाय कुछ काम के संस्करण का उपयोग करने के लिए होगा tee
स्टीवन लू

2
@ सीन लू: डेबियन आधारित डिस्ट्रोस को छोड़कर हर वितरण पर पैकेज spongeका हिस्सा है moreutilsmoreutilsऐसे ही और अधिक आम उपकरण के साथ बराबरी पर हैं कुछ बहुत अच्छा उपकरण है xargsऔर tee
स्विस

10
कैसे इस उर्फ ​​का विस्तार करने के लिए भी वर्तमान बफर को स्वचालित रूप से परिवर्तित फ़ाइल सामग्री लोड करने के लिए विम बता? यह मुझे इसके लिए पूछता है, इसे कैसे स्वचालित करना है?
ज़्लातको

10
@ user247077: उस स्थिति में, catरूट के रूप में चलता है, और आउटपुट शेल द्वारा पुनर्निर्देशित किया जाता है, जो रूट के रूप में नहीं चलता है। यह वैसा ही है echo hi > /read/only/file
WhyNotHugo

99

निष्पादित कमांड लाइन में, वर्तमान फ़ाइल नाम% के लिए खड़ा है । इसमें प्रलेखित है ::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.

जैसा कि आपने पहले ही पता लगा लिया है, :w !cmdवर्तमान बफर की सामग्री को किसी अन्य कमांड में पाइप करता है। क्या teeहै एक या अधिक फ़ाइलों के लिए मानक इनपुट की प्रतिलिपि, और मानक आउटपुट के लिए भी। इसलिए, रूट होने के दौरान:w !sudo tee % > /dev/null वर्तमान बफर की सामग्री को वर्तमान फ़ाइल में प्रभावी रूप से लिखता है । इसके लिए एक और कमांड का इस्तेमाल किया जा सकता है :dd

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

शॉर्टकट के रूप में, आप इस मैपिंग को अपने साथ जोड़ सकते हैं .vimrc:

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

ऊपर के साथ आप :w!!<Enter>फ़ाइल को रूट के रूप में सहेजने के लिए टाइप कर सकते हैं ।


1
दिलचस्प है, :help _%जो आपने दर्ज किया है, उसे :help %ऊपर लाता है , लेकिन ब्रेस-मैचिंग कुंजी लाता है। मैंने अंडरस्कोर उपसर्ग की कोशिश करने के लिए नहीं सोचा होगा, क्या यह विम दस्तावेज़ में किसी प्रकार का एक पैटर्न है? क्या कोई अन्य 'विशेष' चीजें हैं जो मदद की तलाश में हैं?
डेविड पोप

2
@ डेविड: helpकमांड एक टैग पर कूदता है। आप के साथ उपलब्ध टैग देख सकते हैं :h help-tags। आप मिलान टैग देखने के लिए कमांड लाइन पूर्णता का भी उपयोग कर सकते हैं: :h cmdline<Ctrl-D>(या :h cmdline<Tab>यदि आप wildmodeतदनुसार सेट करते हैं )
यूजीन यारमैश

1
मुझे cmap w!! w !sudo tee % > /dev/nullयह काम करने के लिए अपने .vimrc फ़ाइल में उपयोग करना पड़ा । क्या %उपरोक्त उत्तर में गलत लिखा गया है? (यहां कोई विशेषज्ञ नहीं है।)
dmmfll

@DMfll हाँ, यह है। जवाब में आदेश परिणाम होगा sudo tee > /dev/null /path/to/current/fileजिसमें वास्तव में कोई मतलब नहीं है। (इसे संपादित करने जा रहे हैं)
jazzpi

1
@ जैज़ीपी: तुम गलत हो। शेल वास्तव में परवाह नहीं करते हैं कि कमांड लाइन पर आप फ़ाइल पुनर्निर्देशन कहाँ करते हैं।
यूजीन यमश

19

यह भी अच्छी तरह से काम करता है:

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

यह @ नथन लोंग की टिप्पणी से प्रेरित है।

सूचना :

"इसके बजाय इसका उपयोग किया जाना चाहिए 'क्योंकि हम %शेल में जाने से पहले विस्तारित होना चाहते हैं ।


11
जबकि यह काम कर सकता है, यह कई कार्यक्रमों (श और बिल्ली) के लिए सुडो एक्सेस भी देता है। अन्य उदाहरण पैठ-संशोधन के हमलों को रोकने के teeसाथ प्रतिस्थापित करके अधिक सुरक्षित हो सकते हैं /usr/bin/tee
idbrii

18

:w - एक फाइल लिखें।

!sudo - शेल सूडो कमांड को कॉल करें।

tee- लिखने का आउटपुट (vim: w) टी का उपयोग करके पुनर्निर्देशित कमांड। % कुछ भी नहीं है, लेकिन वर्तमान फ़ाइल नाम /etc/apache2/conf.d/mediawiki.conf है। दूसरे शब्दों में टी कमांड को रूट के रूप में चलाया जाता है और यह मानक इनपुट लेता है और इसे% द्वारा दर्शाई गई फ़ाइल में लिखता है। हालाँकि, यह फिर से फ़ाइल को फिर से लोड करने के लिए संकेत देगा (L अपने आप में बदलावों को लोड करने के लिए हिट करें):

ट्यूटोरियल लिंक


9

स्वीकृत उत्तर यह सब कवर करता है, इसलिए मैं सिर्फ एक शॉर्टकट का एक और उदाहरण दूंगा जो मैं उपयोग करता हूं, रिकॉर्ड के लिए।

इसे अपने etc/vim/vimrc(या ~/.vimrc) में जोड़ें :

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

कहाँ पे:

  • cnoremap: विम को बताता है कि कमांड लाइन में निम्नलिखित शॉर्टकट को जोड़ा जाना है।
  • w!!: शॉर्टकट ही।
  • execute '...': एक कमांड जो निम्नलिखित स्ट्रिंग को निष्पादित करता है।
  • silent!: इसे चुपचाप चलाओ
  • write !sudo tee % >/dev/null: ओपी सवाल, NULLएक स्वच्छ आदेश बनाने के लिए संदेशों का पुनर्निर्देशन जोड़ा
  • <bar> edit!: यह चाल केक की चेरी है: यह editबफर को फिर से लोड करने के लिए भी कमांड को कॉल करता है और फिर संदेशों जैसे कि बफर बदल गया है से बचें । यहाँ दो कमांड को अलग करने के <bar>लिए पाइप सिंबल कैसे लिखना है।

आशा है ये मदद करेगा। अन्य समस्याओं के लिए भी देखें:


चुप! पासवर्ड प्रॉम्प्ट को अक्षम कर दिया ताकि आप इसे न देखें
एंडी रे

7

मैं "Oups मैं sudoअपनी फ़ाइल खोलते समय लिखना भूल गया था " के लिए एक और दृष्टिकोण का सुझाव देना चाहता हूं :

एक प्राप्त करने के बजाय permission denied, और टाइप करने के लिए :w!!, मुझे एक सशर्त vimआदेश प्राप्त करने के लिए और अधिक सुरुचिपूर्ण लगता है जो sudo vimफ़ाइल स्वामी है root

इसे लागू करना इतना आसान है (और भी सुरुचिपूर्ण कार्यान्वयन हो सकते हैं, मैं स्पष्ट रूप से बैश-गुरु नहीं हूं):

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

और यह वास्तव में अच्छी तरह से काम करता है।

यह एक-से-अधिक bashसंगृहीत दृष्टिकोण है, vimताकि हर कोई इसे पसंद न करे।

बेशक:

  • ऐसे उपयोग मामले हैं जहां यह विफल हो जाएगा (जब फ़ाइल स्वामी की rootआवश्यकता नहीं है sudo, लेकिन फ़ंक्शन को वैसे भी संपादित किया जा सकता है)
  • यह का उपयोग करते समय मतलब नहीं है vimपढ़ने-केवल एक फ़ाइल के लिए (जहाँ तक मेरा सवाल है, मैं का उपयोग करें tailया catछोटे फ़ाइलों के लिए)

लेकिन मुझे लगता है कि यह एक बहुत अच्छा देव उपयोगकर्ता अनुभव लाता है , जो कुछ ऐसा है जिसका उपयोग करते समय IMHO भूल जाता है bash। :-)


5
बस ध्यान रखें कि यह बहुत कम क्षमा है। व्यक्तिगत रूप से, मेरी अधिकांश गलतियाँ मूर्खतापूर्ण गलतियाँ हैं। इसलिए जब मैं कुछ ऐसा कर रहा होता हूं, जिसमें मैं बेवकूफ और परिणामी हो सकता हूं। यह निश्चित रूप से प्राथमिकता का विषय है, लेकिन विशेषाधिकार बढ़ाना एक कर्तव्यनिष्ठ कार्य है। भी: यदि आप इसे बनाने के लिए इतनी बार ": w !!" चुपचाप ऑटो सुडो को परेशान करने के लिए पर्याप्त है (लेकिन केवल अगर मालिक = जड़); आप अपने वर्तमान वर्कफ़्लो की जांच करना चाहते हैं।
पेनी

दिलचस्प टिप्पणी, हालांकि कोई भी सचेत होगा क्योंकि जब फ़ाइल को rootपासवर्ड के रूप में खोला जा रहा है।
ऑगस्टिन रिडिंगर

आह! वहाँ अंतर है। यह निर्भर करता है कि sudo उपयोगकर्ता के पास "NOPASSWD" सेट है या नहीं।
पेन्ह

तब NOPASSWD होने है क्या कम क्षमाशील है ... :)
ऑगस्टिन Riedinger

4

NEOVIM के लिए

इंटरएक्टिव कॉल ( https://github.com/neovim/neovim/issues/1716 ) के साथ समस्याओं के कारण , मैं डॉ। बेको के जवाब के आधार पर, नवविराम के लिए इसका उपयोग कर रहा हूं:

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

यह ssh-askpasssudo पासवर्ड के लिए पूछकर एक डायलॉग खोलेगा ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.