Загальні каверзи
Найпоширеніший спосіб вирішити проблему з файлом, доступним лише для читання, - це відкрити трубку для поточного файлу як суперкористувача за допомогою реалізації sudo tee
. Однак усі найпопулярніші рішення, які я знайшов в Інтернеті, містять декілька можливих застережень:
- Весь файл надходить до терміналу, а також файл. Для великих файлів це може бути повільним, особливо при повільних мережевих з'єднаннях.
- Файл втрачає свої режими та подібні атрибути.
- Шлях до файлів з незвичайними символами чи пробілами може бути неправильно оброблений
Рішення
Щоб обійти всі ці проблеми, ви можете скористатися такою командою:
" 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'
Їх можна скоротити, з повагою:
:sil exec 'w !sudo tee ' . shellescape(@%, 1) . ' >/dev/null'
:sil exec 'w !sudo tee ' . shellescape(@%, 1) . ' >NUL'
Пояснення
:
починає команду; вам потрібно буде ввести цей символ у звичайному режимі, щоб почати вводити команду. Це слід опустити в сценаріях.
sil[ent]
пригнічує вихід з команди. У цьому випадку ми хочемо зупинити відповідний Press any key to continue
рядок, який з’являється після запуску :!
команди.
exec[ute]
виконує рядок як команду. Ми не можемо просто запустити, :write
оскільки він не обробить необхідний виклик функції.
!
представляє :!
команду: єдина команда, яка :write
приймає. Зазвичай :write
приймає шлях до файлу, до якого потрібно писати. :!
самостійно виконує команду в оболонці (наприклад, використовуючи bash -c
). З :write
, він запустить команду в оболонці, а потім запише весь файл у stdin
.
sudo
повинно бути очевидним, адже саме тому ти тут. Виконайте команду як суперкористувач. У мережі багато інформації про те, як це працює.
tee
труби stdin
до заданого файлу. :write
напише в stdin
, тоді суперкористувач tee
отримає вміст файлу і напише файл. Він не створить новий файл - просто перезапишіть вміст, тому режими та атрибути файлів будуть збережені.
shellescape()
уникає спеціальних символів у заданому шляху до файлу відповідно до поточної оболонки. За допомогою лише одного параметра він, як правило, просто додає шлях у лапки. Оскільки ми надсилаємо командний рядок з повною оболонкою, ми хочемо передати ненульове значення в якості другого аргументу, щоб увімкнути зворотну косу риску інших спеціальних символів, які в іншому випадку можуть відключити оболонку.
@%
зчитує вміст %
регістра, який містить ім'я файлу поточного буфера. Це не обов'язково абсолютний шлях, тому переконайтеся, що ви не змінили поточний каталог. У деяких рішеннях ви побачите пропущений символ комерційного коду. Залежно від місця розташування, %
є дійсним виразом і має такий же ефект, як і читання %
регістра. Однак, вкладений в інший вираз, ярлик, як правило, заборонено: наприклад, у цьому випадку.
>NUL
і >/dev/null
перенаправити stdout
на нульовий пристрій платформи. Незважаючи на те, що ми замовкли команду, ми не хочемо, щоб усі накладні витрати, пов’язані з переходом stdin
назад до vim, - найкраще скинути її якомога раніше. NUL
є нульовим пристроєм у DOS, MS-DOS та Windows, не є дійсним файлом. Згідно з перенаправленнями Windows 8 на NUL, файл із назвою NUL не записується. Спробуйте створити файл на своєму робочому столі під назвою NUL з розширенням або без нього: ви не зможете це зробити. (У ОС Windows є кілька інших імен пристроїв, з якими, можливо, варто ознайомитися.)
~ / .vimrc
Платформа-залежна
Звичайно, ви все ще не хочете запам'ятовувати їх і вводити їх кожен раз. Набагато простіше зіставити відповідну команду на більш просту команду користувача. Для цього на POSIX ви можете додати наступний рядок у ~/.vimrc
файл, створивши його, якщо він ще не існує:
command W silent execute 'write !sudo tee ' . shellescape(@%, 1) . ' >/dev/null'
Це дозволить вам набрати команду: W (залежно від регістру), щоб записати поточний файл із дозволами суперкористувача - набагато простіше.
Платформа-незалежна
Я використовую незалежний від платформи ~/.vimrc
файл, який синхронізується на комп’ютерах, тому я додав багатофункціональну функціональність. Ось ~/.vimrc
лише з відповідними налаштуваннями:
#!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