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 continue
lờ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 :write
vì 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 :write
chấp nhận. Thông thường, :write
chấ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
.
sudo
nê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. :write
sẽ ghi vào stdin
, sau đó siêu người dùng tee
sẽ 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
và >/dev/null
chuyể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 stdin
trở lại vim - tốt nhất là bỏ nó càng sớm càng tốt. NUL
là 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 ~/.vimrc
tệ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 ~/.vimrc
tệ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 ~/.vimrc
chỉ 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