it-swarm.asia

كيف تعمل الحيلة "الكتابة مع سودو"؟

ربما رأى الكثير منكم الأمر الذي يسمح لك بالكتابة على ملف يحتاج إلى إذن جذر ، حتى عندما نسيت فتح vim باستخدام Sudo:

: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 teetee بامتيازات المسؤول.

لكي يفهم الجميع ، يجب أن يخرج % اسم الملف (كمعلمة لـ tee) ، لكن لا يمكنني العثور على مراجع حول المساعدة لهذا السلوك.

tl؛ dr هل يمكن أن يساعدني أحدهم في تشريح هذا الأمر؟

1271
Doppelganger

في :w !Sudo tee %...

% تعني "الملف الحالي"

كما أشار eugene y ، فإن % تعني بالفعل "اسم الملف الحالي". استخدام آخر لهذا في فيم هو في أوامر الاستبدال. على سبيل المثال ، يعني :%s/foo/bar "في الملف الحالي ، استبدل تكرارات foo بـ bar." إذا قمت بتمييز بعض النصوص قبل كتابة :s ، فسترى أن الخطوط المميزة ستحل محل % كنطاق بديل.

لا يقوم :w بتحديث ملفك

يتمثل أحد الجوانب المربكة في هذه الخدعة في أنك قد تعتقد أن :w يعدّل ملفك ، لكنه ليس كذلك. إذا قمت بفتح وتعديل file1.txt ، ثم ركضت :w file2.txt ، فسيكون ذلك "حفظ باسم" ؛ لن يتم تعديل file1.txt ، ولكن سيتم إرسال محتويات المخزن المؤقت الحالي إلى file2.txt.

بدلاً من file2.txt ، يمكنك استبدال أمر Shell لاستلام محتويات المخزن المؤقت. على سبيل المثال ، :w !cat سيعرض المحتويات فقط.

إذا لم يتم تشغيل Vim باستخدام وصول سودو ، فلن تتمكن :w من تعديل ملف محمي ، ولكن إذا نقلت محتويات المخزن المؤقت إلى Shell ، يتم تشغيل أمر في Shell يمكن باستخدام Sudo. في هذه الحالة ، نستخدم tee.

فهم المحملة

بالنسبة لـ tee ، صور أمر tee كأنبوب على شكل حرف T في وضع مواسير bash عادي: يوجه الإخراج إلى ملف (ملفات) محدد و يرسله أيضًا إلى الإخراج القياسي ، والذي يمكن التقاطه بواسطة الأنابيب التالية أمر.

على سبيل المثال ، في ps -ax | tee processes.txt | grep 'foo' ، ستتم كتابة قائمة العمليات في ملف نصي و يتم تمريرها إلى grep.

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

(تم إنشاء مخطط باستخدام Asciiflow .)

راجع tee man صفحة لمزيد من المعلومات.

كوم كاختراق

في الحالة التي يصفها سؤالك ، استخدام 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بشكل صريح يزيل الإخراج القياسي ، لأنه ، كما قلت ، لسنا بحاجة إلى تمرير أي شيء إلى أمر آخر متصل بالأنابيب.

1435
Nathan Long

في سطر الأوامر المنفذة ، يرمز % إلى اسم الملف الحالي . تم توثيقه في :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> لحفظ الملف كجذر.

93
Eugene Yarmash

هذا يعمل أيضا بشكل جيد:

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

هذا مستوحى من تعليق @ Nathan Long.

تنويه:

يجب استخدام " بدلاً من ' لأننا نريد توسيع % قبل الانتقال إلى Shell.

18
feihu

:w - كتابة ملف.

!Sudo - استدعاء الأوامر شل سودو.

tee - إعادة توجيه إخراج الكتابة (vim: w) باستخدام نقطة الإنطلاق. ٪ ليس سوى اسم الملف الحالي ، مثل /etc/Apache2/conf.d/mediawiki.conf. بمعنى آخر ، يتم تشغيل الأمر tee كجذر ويستغرق إدخالًا قياسيًا وكتابته إلى ملف يمثله٪. ومع ذلك ، سيؤدي هذا إلى إعادة تحميل الملف مرة أخرى (اضغط L لتحميل التغييرات في vim نفسه):

رابط تعليمي

16
kev

تغطي الإجابة المقبولة كل شيء ، لذلك سأقدم فقط مثالًا آخر على اختصار أستخدمه للسجل.

أضفه إلى etc/vim/vimrc (أو ~/.vimrc):

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

أين:

  • cnoremap: يخبر vim أن الاختصار التالي سيتم ربطه في سطر الأوامر.
  • w!!: الاختصار نفسه.
  • execute '...': أمر يقوم بتنفيذ السلسلة التالية.
  • silent!: قم بتشغيله بصمت
  • write !Sudo tee % >/dev/null: سؤال OP ، أضاف إعادة توجيه للرسائل إلى NULL لإجراء أمر نظيف
  • <bar> edit!: هذه الخدعة هي كرز الكعكة: وهي تستدعي أيضًا الأمر edit لإعادة تحميل المخزن المؤقت ثم تجنب الرسائل مثل تم تغيير المخزن المؤقت. <bar> هو كيفية كتابة رمز توجيه الإخراج لفصل أمرين هنا.

آمل أن يساعد. انظر أيضا لمشاكل أخرى:

5
Dr Beco

أود أن أقترح طريقة أخرى ل "Oups نسيت أن أكتب Sudo أثناء فتح ملفي" المشكلة:

بدلاً من تلقي permission denied ، والحاجة إلى كتابة :w!! ، أجد أنه من الأفضل أن يكون لدي أمر vim مشروط يعمل Sudo vim إذا كان مالك الملف root.

هذا سهل التنفيذ (قد يكون هناك تطبيقات أكثر أناقة ، من الواضح أنني لست خبيراً في bash-guru):

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. :-)

3
Augustin Riedinger