Câu hỏi Làm thế nào để vim "viết với sudo" lừa làm việc?


Nhiều người trong số các bạn có thể đã thấy lệnh cho phép bạn viết trên một tệp cần quyền root, ngay cả khi bạn quên mở vim bằng sudo:

:w !sudo tee %

Vấn đề là tôi không hiểu chính xác những gì đang diễn ra ở đây.

Tôi đã tìm ra điều này: w là cho điều này

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

vì vậy nó vượt qua tất cả các dòng như đầu vào tiêu chuẩn.

Các !sudo tee một phần cuộc gọi tee với quyền quản trị viên.

Để tất cả có ý nghĩa, % nên xuất tên tệp (dưới dạng tham số cho tee), nhưng tôi không thể tìm thấy tài liệu tham khảo về trợ giúp cho hành vi này.

tl; dr Ai đó có thể giúp tôi giải phẫu lệnh này?


1152
2018-04-08 14:36


gốc


@Nathan: Sẽ :w !sudo cat > % không hoạt động tốt, và không gây ô nhiễm đầu ra tiêu chuẩn? - Bjarke Freund-Hansen
@ bjarkef - không, điều đó không hiệu quả. Trong trường hợp đó, sudo Được áp dụng cho cat, nhưng không >, vì vậy nó không được phép. Bạn có thể thử chạy toàn bộ lệnh trong một sudo subshell, như :w !sudo sh -c "cat % > yams.txt", nhưng điều đó cũng không hiệu quả, bởi vì trong subshell, % là không; bạn sẽ bỏ trống nội dung của tệp. - Nathan Long
@NathanLong: Bạn có thể sử dụng :w !sudo sh -c 'cat $1 > yams.txt' - %, nhưng tôi không biết làm thế nào để xử lý các ký tự đặc biệt hoặc khoảng trắng - knittl
Tôi chỉ muốn thêm rằng sau khi gõ lệnh đó, một thông điệp cảnh báo có thể xuất hiện. Nếu vậy, nhấn L. Sau đó, bạn sẽ được yêu cầu nhấn enter. Làm và cuối cùng bạn sẽ lưu tệp của mình. - pablofiumara
@NathanLong @knittl: :w !sudo sh -c "cat >%" thực sự hoạt động tốt như sudo tee % vì Vim thay thế tên tệp cho % trước khi nó đến được subshell. Tuy nhiên, không ai trong số họ làm việc nếu tên tập tin có không gian trong đó; bạn phải làm :w !sudo sh -c "cat >'%'" hoặc là :w !sudo tee "%" để khắc phục điều đó. - Han Seoul-Oh


Các câu trả lời:


Trong :w !sudo tee %...

% có nghĩa là "tệp hiện tại"

Như eugene y chỉ ra, % thực sự có nghĩa là "tên tệp hiện tại". Một cách sử dụng khác cho điều này trong Vim là trong các lệnh thay thế. Ví dụ, :%s/foo/bar có nghĩa "trong tệp hiện tại, thay thế các lần xuất hiện của foo với bar"Nếu bạn đánh dấu một số văn bản trước khi nhập :s, bạn sẽ thấy rằng các dòng được đánh dấu thay thế % làm phạm vi thay thế của bạn.

:w không cập nhật tệp của bạn

Một phần khó hiểu của mẹo này là bạn có thể nghĩ :w đang sửa đổi tệp của bạn, nhưng nó không phải là. Nếu bạn đã mở và sửa đổi file1.txt, sau đó chạy :w file2.txt, nó sẽ là một "tiết kiệm như"; file1.txt sẽ không được sửa đổi, nhưng nội dung bộ đệm hiện tại sẽ được gửi đến file2.txt.

Thay vì file2.txt, bạn có thể thay thế một lệnh shell để nhận nội dung bộ đệm. Ví dụ, :w !cat sẽ chỉ hiển thị nội dung.

Nếu Vim không chạy với truy cập sudo, :w không thể sửa đổi tệp được bảo vệ, nhưng nếu nó chuyển nội dung đệm vào vỏ, một lệnh trong shell có thể được chạy với sudo. Trong trường hợp này, chúng tôi sử dụng tee.

Hiểu biết về tee

Như cho tee, hình ảnh tee lệnh như một đường ống hình chữ T trong tình huống đường ống bash bình thường: nó hướng đầu ra tới các tệp đã chỉ định và cũng gửi nó đến đầu ra tiêu chuẩn, có thể được chụp bằng lệnh đường ống tiếp theo.

Ví dụ, trong ps -ax | tee processes.txt | grep 'foo', danh sách các quy trình sẽ được ghi vào một tệp văn bản  chuyển đến grep.

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

(Sơ đồ được tạo bằng Asciiflow.)

Xem tee trang người đàn ông để biết thêm thông tin.

Tee như một hack

Trong trường hợp câu hỏi của bạn mô tả, sử dụng tee là một hack vì chúng tôi bỏ qua một nửa những gì nó làm. sudo tee ghi vào tệp của chúng tôi và cũng gửi nội dung đệm đến đầu ra tiêu chuẩn, nhưng chúng tôi bỏ qua đầu ra tiêu chuẩn. Chúng ta không cần truyền bất cứ thứ gì cho một lệnh piped khác trong trường hợp này; chúng tôi chỉ sử dụng tee như một cách khác để viết một tệp và để chúng tôi có thể gọi nó bằng sudo.

Làm cho thủ thuật này trở nên dễ dàng

Bạn có thể thêm nó vào .vimrc để làm cho mẹo này trở nên dễ sử dụng: chỉ cần gõ :w!!.

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

Các > /dev/nullphần một cách rõ ràng ném đi đầu ra tiêu chuẩn, vì, như tôi đã nói, chúng ta không cần truyền bất cứ thứ gì cho một lệnh piped khác.


1276
2017-08-16 12:49



Đặc biệt như ký hiệu của bạn "w !!" dễ nhớ như vậy sau khi sử dụng "sudo !!" trên dòng lệnh. - Aidan Kane
Vì vậy, điều này sử dụng tee cho khả năng viết stdin vào một tập tin. Tôi ngạc nhiên không có một chương trình nào có công việc để làm điều đó (tôi đã tìm thấy một chương trình mà tôi chưa từng nghe đến sponge mà thực hiện điều này). Tôi đoán điển hình "viết một luồng vào một tệp" được thực hiện bởi một trình bao tích hợp sẵn. Vim có !{cmd} không ngã ba một vỏ (forking cmd thay thế)? Có lẽ điều gì đó rõ ràng hơn sẽ là sử dụng một số biến thể hoạt động của sh -c ">" thay vì tee. - Steven Lu
@Steven Lu: sponge Là một phần của moreutils gói phần mềm trên mọi phân phối ngoại trừ các bản phân phối dựa trên Debian. moreutils có một số công cụ khá đẹp, ngang bằng với các công cụ phổ biến hơn như xargs và tee. - Swiss
Làm thế nào để mở rộng bí danh này cũng cho vim tự động tải nội dung tập tin đã thay đổi vào bộ đệm hiện tại? Nó hỏi tôi về nó, làm thế nào để tự động hóa nó? - Zlatko
@ user247077: Trong trường hợp đó, cat chạy dưới dạng root và đầu ra được chuyển hướng bởi shell, không chạy dưới dạng root. Nó giống như echo hi > /read/only/file. - WhyNotHugo


Trong dòng lệnh đã thực thi, % viết tắt của tên tệp hiện tại. Đây là tài liệu trong :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.

Như bạn đã phát hiện ra, :w !cmd đường dẫn nội dung của bộ đệm hiện tại sang lệnh khác. Gì tee không sao chép đầu vào tiêu chuẩn vào một hoặc nhiều tệp và cũng với đầu ra tiêu chuẩn. Vì thế, :w !sudo tee % > /dev/null ghi hiệu quả nội dung của bộ đệm hiện tại vào tệp hiện tại trong khi là gốc. Một lệnh khác có thể được sử dụng cho điều này là dd:

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

Là lối tắt, bạn có thể thêm ánh xạ này vào .vimrc:

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

Với ở trên, bạn có thể nhập :w!!<Enter> để lưu tệp dưới dạng gốc.


88
2018-04-08 14:45



Hấp dẫn, :help _% mang lại những gì bạn đã nhập, nhưng :help % đưa ra khóa khớp lệnh. Tôi sẽ không nghĩ để thử tiền tố gạch dưới, là một mô hình của một số loại trong tài liệu vim? Có điều gì khác 'đặc biệt' để thử khi tìm kiếm sự giúp đỡ không? - David Pope
@David: The help lệnh nhảy vào thẻ. Bạn có thể xem các thẻ có sẵn với :h help-tags. Bạn cũng có thể sử dụng hoàn thành dòng lệnh để xem các thẻ phù hợp: :h cmdline<Ctrl-D> (hoặc là :h cmdline<Tab> nếu bạn đặt wildmode theo đó) - Eugene Yarmash
+1 cho :h help-tags, có thể tìm kiếm và hữu ích. Cảm ơn! - David Pope
Tôi đã phải sử dụng cmap w!! w !sudo tee % > /dev/null trong tập tin .vimrc của tôi để thực hiện công việc này. Là %thất lạc trong câu trả lời ở trên? (Không có chuyên gia vim ở đây.) - DMfll
@jazzpi: Bạn sai rồi. Shell không thực sự quan tâm ở đâu trên dòng lệnh bạn thực hiện chuyển hướng tệp. - Eugene Yarmash


Điều này cũng hoạt động tốt:

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

Điều này được lấy cảm hứng từ nhận xét của @Nathan Long.

ĐỂ Ý:

" phải được sử dụng thay vì ' bởi vì chúng tôi muốn % được mở rộng trước khi chuyển đến trình bao.


18
2017-07-29 08:08



Trong khi điều này có thể làm việc, nó cũng cho phép truy cập sudo vào nhiều chương trình (sh và cat). Các ví dụ khác có thể an toàn hơn bằng cách thay thế tee với /usr/bin/tee để ngăn chặn các cuộc tấn công sửa đổi PATH. - idbrii


:w - Viết một tập tin.

!sudo - Gọi lệnh sudo shell.

tee - Đầu ra của lệnh write (vim: w) được chuyển hướng bằng tee. % Không là gì ngoài tên tệp hiện tại tức là /etc/apache2/conf.d/mediawiki.conf. Nói cách khác, lệnh tee được chạy dưới dạng root và nó lấy đầu vào tiêu chuẩn và ghi nó vào một tệp được biểu diễn bằng%. Tuy nhiên, điều này sẽ nhắc nhở để tải lại tệp một lần nữa (nhấn L để tải thay đổi trong vim chính nó):

liên kết hướng dẫn


16
2018-06-04 06:02





Câu trả lời được chấp nhận bao gồm tất cả, vì vậy tôi sẽ đưa ra một ví dụ khác về đường tắt mà tôi sử dụng, để ghi lại.

Thêm nó vào etc/vim/vimrc (hoặc là ~/.vimrc):

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

Ở đâu:

  • cnoremap: nói vim rằng phím tắt sau đây sẽ được liên kết trong dòng lệnh.
  • w!!: chính phím tắt.
  • execute '...': một lệnh thực hiện chuỗi sau.
  • silent!: chạy âm thầm
  • write !sudo tee % >/dev/null: câu hỏi OP, đã thêm một chuyển hướng thư đến NULL để làm cho một lệnh sạch
  • <bar> edit!: thủ thuật này là bánh anh đào: nó cũng gọi edit lệnh để tải lại bộ đệm và sau đó tránh các thông báo như bộ đệm đã thay đổi. <bar> là cách viết ống biểu tượng để tách hai lệnh ở đây.

Hy vọng nó giúp. Xem thêm cho các vấn đề khác:


3
2018-01-13 07:12





Tôi muốn đề xuất một cách tiếp cận khác cho "Oups tôi quên viết sudo khi mở tệp của tôi " vấn đề:

Thay vì nhận được permission deniedvà phải nhập :w!!, Tôi thấy nó thanh lịch hơn để có điều kiện vim lệnh nào sudo vim nếu chủ sở hữu tệp là root.

Điều này là dễ thực hiện (thậm chí có thể có nhiều triển khai thanh lịch hơn, tôi rõ ràng không phải là bash-guru):

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

Và nó hoạt động rất tốt.

Đây là một bashcách tiếp cận -center hơn là vim-Một cái không phải ai cũng thích.

Tất nhiên:

  • có những trường hợp sử dụng mà nó sẽ thất bại (khi chủ sở hữu tệp không root nhưng yêu cầu sudonhưng chức năng vẫn có thể được chỉnh sửa)
  • nó không có ý nghĩa khi sử dụng vim chỉ đọc một tệp (theo như tôi quan tâm, tôi sử dụng tail hoặc là cat cho các tệp nhỏ)

Nhưng tôi thấy điều này mang lại một tốt hơn nhiều trải nghiệm người dùng dev, cái gì đó mà IMHO có xu hướng bị lãng quên khi sử dụng bash. :-)


1
2018-02-28 18:21