Lấy quyền root trên một tập tin bên trong vi? [đóng cửa]


245

Thông thường trong khi chỉnh sửa tập tin cấu hình, tôi sẽ mở một tệp bằng vi và sau đó khi tôi đi lưu nó nhận ra rằng tôi đã không gõ

sudo vi filename

Có cách nào để cung cấp đặc quyền vi sudo để lưu tệp không? Tôi dường như nhớ lại đã thấy một cái gì đó về điều này trong khi tìm kiếm một số thứ về vi cách đây một thời gian, nhưng bây giờ tôi không thể tìm thấy nó.


có thể chỉ cần lưu một bản sao trong thư mục nhà của bạn và "sudo mv" nó sau
paan

Câu trả lời:


296

% được thay thế bằng tên tệp hiện tại, do đó bạn có thể sử dụng:

:w !sudo tee %

( vimsẽ phát hiện ra rằng tập tin đã được thay đổi và hỏi bạn có muốn tải lại không. Nói có bằng cách chọn [L]chứ không phải OK.)

Là một phím tắt, bạn có thể xác định lệnh của riêng bạn. Đặt những điều sau vào .vimrc:

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

Với những điều trên bạn có thể gõ :W<Enter>để lưu tập tin. Kể từ khi tôi viết bài này, tôi đã tìm thấy một cách đẹp hơn (theo ý kiến ​​của tôi) để làm điều này:

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

Bằng cách này, bạn có thể nhập :w!!và nó sẽ được mở rộng thành dòng lệnh đầy đủ, để lại con trỏ ở cuối, vì vậy bạn có thể thay thế %bằng tên tệp của riêng bạn, nếu bạn muốn.


5
Điều này có hoạt động trong gvim? Chạy lệnh khiến Vim nhắc mật khẩu nhưng không chấp nhận đầu vào. Cuối cùng, nó cũng dừng lại ở hai lần thử và nói:sudo: 1 incorrect password attempt
cmcginty

tôi sẽ thấy không có lý do gì để gvim cư xử khác đi ... bạn có chắc rằng sudo tự hoạt động chính xác không?

Nếu bạn cần quyền root để lưu tệp mới, hãy thay thế% bằng tên (bao gồm đường dẫn) của tệp mới.
gvkv

Đôi khi, bạn cần thêm người dùng của mình vào tệp sudoer trước, nhập người dùng root và mở /etc/sudoerstệp, thêm vào your_username ALL=(ALL) ALLdưới dòng root ALL=(ALL) ALL, thoát và lưu.
tuyệt nhất

1
@coolesting: 1) có khoảng một nghìn thứ khác bạn cần làm, chúng tôi không thể liệt kê tất cả. 2) bạn nên luôn luôn sử dụng visudo.

32

Nói chung, bạn không thể thay đổi id người dùng hiệu quả của quy trình vi, nhưng bạn có thể làm điều này:

:w !sudo tee myfile

1
:w !sudo tee % >/dev/nullhoặc :w !sudo dd of=%tránh để nội dung của tệp bị dội lại khi tệp được lưu.
jamessan

Bạn có thể giải thích làm thế nào điều này hoạt động? Tôi nhìn lên teevà thấy đó là lệnh ống Unix và !chèn lệnh shell. Là :wvăn bản để tiêu chuẩn ra, mà được dẫn bởi tee?
Eric Hu

4
@Eric, đúng vậy. lệnh "tee myfile" sẽ sao chép stdin vào myfile. chạy "sudo tee myfile" sẽ làm tương tự, nhưng vì quy trình phát bóng được sở hữu bởi root, myfile cũng sẽ được sở hữu bởi root. Về phía vi, ": w! Một số dòng lệnh" sẽ chuyển tất cả các dòng thành "một số dòng lệnh".
Đánh dấu Harrison

16

Thông thường

Phương pháp phổ biến nhất để khắc phục sự cố tệp chỉ đọc là mở một đường ống đến tệp hiện tại với tư cách là siêu người dùng sử dụng triển khai sudo tee. Tuy nhiên, tất cả các giải pháp phổ biến nhất mà tôi đã tìm thấy trên Internet đều có sự kết hợp của một số cảnh báo tiềm năng:

  • Toàn bộ tệp được ghi vào thiết bị đầu cuối, cũng như tệp. Điều này có thể chậm đối với các tệp lớn, đặc biệt là trên các kết nối mạng chậm.
  • Các tập tin mất chế độ của nó và các thuộc tính tương tự.
  • Đường dẫn tệp có ký tự hoặc dấu cách khác thường có thể không được xử lý chính xác.

Các giải pháp

Để giải quyết tất cả các vấn đề này, bạn có thể sử dụng lệnh sau:

" 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'

Chúng có thể được rút ngắn, tôn trọng:

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

Giải trình

:bắt đầu mệnh lệnh; bạn sẽ cần nhập ký tự này trong chế độ bình thường để bắt đầu nhập lệnh. Nó nên được bỏ qua trong các kịch bản.

sil[ent]ngăn chặn đầu ra từ lệnh. Trong trường hợp này, chúng tôi muốn dừng Press any key to continuelời nhắc giống như xuất hiện sau khi chạy :!lệnh.

exec[ute]thực hiện một chuỗi như là một lệnh. Chúng ta không thể chạy :writevì nó sẽ không xử lý cuộc gọi chức năng cần thiết.

!đại diện cho :!lệnh: lệnh duy nhất :writechấp nhận. Thông thường, :writechấp nhận một đường dẫn tệp để viết. :!tự nó chạy một lệnh trong shell (ví dụ: bằng cách sử dụng bash -c). Với :write, nó sẽ chạy lệnh trong trình bao, và sau đó ghi toàn bộ tệp vào stdin.

sudonên rõ ràng, vì đó là lý do tại sao bạn ở đây. Chạy lệnh như siêu người dùng. Có rất nhiều thông tin trên mạng về cách thức hoạt động của nó.

teeống dẫn stdinđến tập tin nhất định. :writesẽ ghi vào stdin, sau đó siêu người dùng teesẽ nhận được nội dung tệp và ghi tệp. Nó sẽ không tạo một tệp mới - chỉ ghi đè lên nội dung - vì vậy các chế độ và thuộc tính tệp sẽ được giữ nguyên.

shellescape()thoát các ký tự đặc biệt trong đường dẫn tệp đã cho là phù hợp với trình bao hiện tại. Chỉ với một tham số, thông thường sẽ chỉ bao gồm đường dẫn trong dấu ngoặc kép khi cần thiết. Vì chúng tôi đang gửi đến một dòng lệnh shell đầy đủ, chúng tôi sẽ muốn chuyển một giá trị khác không làm đối số thứ hai để cho phép thoát dấu gạch chéo ngược của các ký tự đặc biệt khác có thể vấp phải vỏ.

@%đọc nội dung của thanh %ghi chứa tên tệp bộ đệm hiện tại. Đây không nhất thiết là một đường dẫn tuyệt đối, vì vậy hãy đảm bảo rằng bạn chưa thay đổi thư mục hiện tại. Trong một số giải pháp, bạn sẽ thấy biểu tượng thương mại bị bỏ qua. Tùy thuộc vào vị trí, %là một biểu thức hợp lệ và có tác dụng tương tự như đọc thanh %ghi. Tuy nhiên, lồng bên trong một biểu thức khác, phím tắt thường không được phép, chẳng hạn như trong trường hợp này.

>NUL>/dev/nullchuyển hướng stdoutđến thiết bị null của nền tảng. Mặc dù chúng tôi đã tắt lệnh, chúng tôi không muốn tất cả các chi phí liên quan đến đường ống stdintrở lại vim - tốt nhất là bỏ nó càng sớm càng tốt. NULlà thiết bị null trên DOS, MS-DOS và Windows, không phải là tệp hợp lệ. Kể từ khi Windows 8 chuyển hướng đến NUL không dẫn đến một tệp có tên NUL được viết. Hãy thử tạo một tệp trên máy tính để bàn của bạn có tên NUL, có hoặc không có phần mở rộng tệp: bạn sẽ không thể làm như vậy. (Có một số tên thiết bị khác trong Windows có thể đáng để biết.)

~ / .vimrc

Phụ thuộc nền tảng

Tất nhiên, bạn vẫn không muốn ghi nhớ chúng và gõ chúng mỗi lần. Việc ánh xạ lệnh thích hợp thành lệnh người dùng đơn giản hơn nhiều. Để thực hiện việc này trên POSIX, bạn có thể thêm dòng sau vào ~/.vimrctệp của mình , tạo nó nếu nó chưa tồn tại:

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

Điều này sẽ cho phép bạn gõ lệnh: W (phân biệt chữ hoa chữ thường) để ghi tệp hiện tại với quyền siêu người dùng - dễ dàng hơn nhiều.

Nền tảng độc lập

Tôi sử dụng một ~/.vimrctệp độc lập với nền tảng đồng bộ hóa trên các máy tính, vì vậy tôi đã thêm chức năng đa nền tảng cho tôi. Đây là một ~/.vimrcchỉ với các cài đặt có liên quan:

#!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

Điều gì sẽ xảy ra nếu bạn truy cập Windows bằng cách thực sự tạo một tệp có thể ghi trên thế giới tại C: \ dev \ null?
Paul Stelian

1
@PaulStelian Có thể, nhưng không thể. Bạn có thể dễ dàng mở rộng mã này để chiếm nhiều nền tảng và hoàn cảnh khác nhau. Trong thực tế, bạn không có khả năng gặp phải tình huống trên Windows sudotồn tại nhưng không /dev/null, vì vậy bạn cần phải nhận fancier nếu bạn muốn hỗ trợ đa nền tảng thực sự. Đó là nhiều hơn một giới thiệu - thực phẩm cho suy nghĩ. :)
Zenexer 6/07/2016

11

Nếu bạn đang sử dụng Vim , có một tập lệnh có sẵn có tên sudo.vim . Nếu bạn thấy rằng bạn đã mở một tệp mà bạn cần quyền truy cập root để đọc, hãy nhập

: e sudo:%
Vim thay thế% bằng tên của tệp hiện tại và sudo:hướng dẫn tập lệnh sudo.vim tiếp quản để đọc và viết.


4
Tôi không khuyên bạn nên sử dụng tập lệnh này vì nó không có biện pháp phòng ngừa thích hợp với việc thoát tên tệp.
jamessan

7

Lời khuyên của Ryan nói chung là tốt, tuy nhiên, nếu làm theo bước 3, đừng di chuyển tệp tạm thời; nó sẽ có quyền sở hữu và quyền sai. Thay vào đó, sudoedittập tin chính xác và đọc trong nội dung (sử dụng :rhoặc tương tự) của tập tin tạm thời.

Nếu theo bước 2, sử dụng :w!để buộc tập tin được ghi.


3

Khi bạn chuyển sang chế độ chèn trên một tệp bạn cần truy cập sudo để chỉnh sửa, bạn sẽ nhận được thông báo trạng thái cho biết

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

Nếu tôi nhớ điều đó, nói chung tôi làm

:w ~/edited_blah.tmp
:q

..sau đó..

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

..hoặc là..

sudo mv edited_blah.tmp /etc/blah

Có lẽ có một cách vòng ít hơn để làm điều đó, nhưng nó hoạt động.


cat $ tmp> $ target là sáng tạo, nhưng có lý do nào để không chỉ sudo mv tệp không?
ojrac

Điểm hay .. Cũng có một vấn đề lớn với sudo cat gì đó> / etc / blah - sẽ sử dụng sudo để cat tệp, sau đó người dùng thông thường ghi vào / etc / blah (không hoạt động) .. Đã sửa nó trong câu trả lời và thêm đề xuất sudo mv tốt hơn của bạn ..
dbr

Đề xuất mv không bảo vệ quyền.
Paul Stelian

1

Google nhanh chóng dường như đưa ra lời khuyên này:

  1. Đừng cố chỉnh sửa nếu nó chỉ đọc.
  2. Bạn có thể thay đổi các quyền trên tệp. (Việc nó có cho phép bạn tiết kiệm hay không là tùy thuộc vào thử nghiệm.)
  3. Nếu bạn vẫn chỉnh sửa, lưu vào một tệp tạm thời và sau đó di chuyển nó.

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



0

Tôi có cái này trong ~ / .bashrc:

alias svim='sudo vim'

Bây giờ bất cứ khi nào tôi cần chỉnh sửa một tập tin cấu hình, tôi chỉ cần mở nó bằng svim.


2
Các sudoeditlệnh nên được ưa thích vì nó không yêu cầu chạy vim như root.
jamessan

2
Điều này vẫn không ngăn bạn buộc vim thay vì svim, đó là điều mà OP đã trốn tránh.
ScaryAardvark

3
-1, Đây chỉ là nói "nhớ gõ sudo khi mở tệp", OP muốn biết làm thế nào họ có thể nhận được quyền root bên trong vi.
Brad Koch

-2

Một cách nhanh chóng mà bạn có thể xem xét là thực hiện một chmod trên tệp bạn đang chỉnh sửa, lưu với vim và sau đó chmod trở lại với tệp ban đầu.

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)

Tất nhiên tôi không khuyến nghị phương pháp này trong một hệ thống mà bạn lo lắng về bảo mật, vì trong vài giây, bất kỳ ai cũng có thể đọc / thay đổi tệp mà bạn không nhận ra.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.