How to change file permission from within vi
Asked Answered
C

9

29

I sometimes open a read-only file in vi, forgetting to do chmod +w before opening it. Is there way to change the file from within vi?

Something like !r chmod +w [filename]?

Is there a shortcut to refer to the currently open file without spelling it's long name?

Cerography answered 22/10, 2009 at 11:41 Comment(0)
P
67

Just use

:!chmod +w %

in command mode. % will be replaced by the current file name.

Pounce answered 22/10, 2009 at 11:44 Comment(2)
Thanks --- this was useful. A minor annoyance is that vim now warns about the need to reload the file (W16). Is there a way to stop it without setting autoread?Pythagoras
@Pythagoras I know it's an old post, but it's worth mentioning for posterity: You could use Tim Pope's Eunuch.vim and then use the :Chmod command. It does exactly what you're wanting.Possessory
R
39

If you have the rights to write to the file, then you can just use exclamation mark to force it:

:w!

If you don't have the rights and need to change user, but still want to write to the file, sometimes you may go for something like

:w !sudo tee %
Rasure answered 22/10, 2009 at 11:56 Comment(3)
You don't want to write to file all the time either ;-)Rasure
:w !sudo tee % sends the file input to tee which then forwards it to the current file %.Taluk
@LuboKanev, that's right. As a side effect tee also writes the file to console, but that's not meant to accomplish anything ;-)Rasure
T
13

I know this is an old post, but with Vim Version8 a function has been included with which you can change file permissions.

According to the version8.txt file:

setfperm() set the permissions of a file

This function can then be called via the "call" command in Vim.

This is done as follows:

:call setfperm("file name","permissions")

The structure of the "permissions" string takes the same form as described in the Vim documentation:

getfperm({fname}) getfperm() The result is a String, which is the read, write, and execute permissions of the given file {fname}. If {fname} does not exist or its directory cannot be read, an empty string is returned. The result is of the form "rwxrwxrwx", where each group of "rwx" flags represent, in turn, the permissions of the owner of the file, the group the file belongs to, and other users. If a user does not have a given permission the flag for this is replaced with the string "-". Example: :echo getfperm("/etc/passwd") This will hopefully (from a security point of view) display the string "rw-r--r--" or even "rw-------".

A minimal example:

:call setfperm("foo.txt","rwxrwxrwx")

This adds read, write and execute permissions to the "foo.txt" file in the current directory.

Talton answered 3/8, 2017 at 14:18 Comment(1)
setfperm() is also present in Vim 7 (at least, 7.4 has it). :call setfperm(expand("%"), "rwxr-xr-x") is one way to set the mode for the current file to 0755, without needing to enter the file's name explicitly.Cretan
T
7

Have you tried

!chmod +w %

The % represents the current filename.

You could also map a key to this like Ctrl-W.

:map <C-w> :!chmod +w %<CR>

Note that you type Ctrl-V Ctrl-M to get the <CR>

Tega answered 22/10, 2009 at 11:53 Comment(0)
R
5

After editing your file with vim, press "esc" and then ":". Then type the following command:

w !sudo tee %

Then press "Enter". Then type

:q!

to successfully exit from the editor.

Rizzio answered 25/10, 2017 at 9:31 Comment(1)
Thanks @Kasumi! This is what I was looking for - how to switch the user and write the file using it's owner (root in my case).Branchia
H
1
:!chmod <perms> <file>

and if vi still doesn't want to write it,

:se cpo-=W
Huddleston answered 22/10, 2009 at 11:42 Comment(0)
T
0

As David pointed out, setfperm() is the way to do this within vim.

Here are the mappings I use to add write or execute permissions to the current file:

function! ChmodPlus(expr, pat)
    let file = expand('%')
    let oldperms = getfperm(file)
    let newperms = substitute(oldperms, a:expr, a:pat, '')
    if (oldperms != newperms)
        call setfperm(file, newperms)
    endif
    echom(printf('Permissions: %s', newperms))
endfunction

function! ChmodPlusX()
    call ChmodPlus('^\(..\).', '\1x')
endfunction

function! ChmodPlusW()
    call ChmodPlus('^\(.\).', '\1w')
endfunction

" Make current file writeable
noremap <silent> <Leader>W :call ChmodPlusW()<CR>

" Make current file executable
noremap <silent> <Leader>X :call ChmodPlusX()<CR>
Teacup answered 17/8, 2019 at 19:28 Comment(0)
D
0

You can also do this with the netrw module that comes with vim if your lazy, example :Texplore followed by scrolling to the file in normal mode and entering gp. Octal or symbolic at least work.

It's a little more intuitive with multiple files but per buffer-window without, use your colon command history to repeat commands.

Dearborn answered 17/2, 2022 at 17:3 Comment(0)
R
0

Based on ideas from several answers here, I'm now using this:

" autoreload file
set autoread

" chmod +x current file
"
" not using setfperm() here to have the behavior of chmod(1), e.g. adding and
" using the umask.
function! ChmodThis(perm)
  if getbufinfo('%')[0].changed
    echo "Modified, save first!"
  else
    call system('chmod ' .. a:perm .. ' -- ' .. expand('%:S'))
    echo "chmod done."
  endif
endfunction
noremap <silent> <Leader>X :call ChmodThis('+x')<CR>
Razzia answered 27/10, 2023 at 20:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.