19

Is there any way to set +x bit on script while creating?

For example I run:

vim -some_option_to_make_file_executable script.sh

and after saving I can run file without any additional movings.

ps. I can run chmod from vim or even from console itself, but this is a little annoying, cause vim suggests to reload file. Also it's annoying to type chmod command every time. pps. It would be great to make it depending on file extension (I don't need executable .txt :-) )

5 Answers 5

27

I don't recall where I found this, but I use the following in my ~/.vimrc

" Set scripts to be executable from the shell
au BufWritePost * if getline(1) =~ "^#!" | if getline(1) =~ "/bin/" | silent !chmod +x <afile> | endif | endif

The command automatically sets the executable bit if the first line starts with "#!" or contains "/bin/".

5
  • 1
    Wow, that's great thing. Btw, seems you can join two if's into one if getline(1) =~ "^#!/bin/". Anyway that's amazing. Thank you.
    – rush
    Jun 4, 2012 at 13:39
  • This is not a "or". I prefer to use just first condition, au BufWritePost * if getline(1) =~ "^#!" | silent !chmod +x % | endif
    – vault
    Feb 17, 2016 at 14:39
  • 1
    @rush The reasons for the double if statements is to to catch lines where the the /bin doesn't immediately follow the shebang, like #!/usr/bin/env. A way around that is of course to use a wildcard: getline(1) =~ "^#!.*/bin/". Apr 2, 2016 at 14:47
  • 2
    Neat trick but I get the following every time I save: written/bin/bash: endif: command not found /bin/bash: endif: command not found
    – StevieD
    Feb 10, 2017 at 21:36
  • 3
    this fixes it: au BufWritePost * if getline(1) =~ "^#!" | if getline(1) =~ "/bin/" | silent execute "!chmod a+x <afile>" | endif | endif
    – StevieD
    Feb 10, 2017 at 21:44
4

I found this script at http://vim.wikia.com. Not a perfect solution, but a acceptable one, I think.

function! SetExecutableBit()
  let fname = expand("%:p")
  checktime
  execute "au FileChangedShell " . fname . " :echo"
  silent !chmod a+x %
  checktime
  execute "au! FileChangedShell " . fname
endfunction
command! Xbit call SetExecutableBit()

You can now set the execute bit with the command :Xbit. All credit to Max Ischenko at vim.wikia.com

1

I wrote myself a version of this that is a bit more selective. It only makes the file executable when writing a new file, and only if it starts with #!. This version also avoids executing an external command, doing everything in pure vimscript.

" automatically make script files executable when writing for the first time
function! NewScriptExec() abort
    " check if this is a new file which starts with a shebang
    if exists('s:new_file') && getline(1)[0:1] == '#!'
        " based on https://stackoverflow.com/a/57539332/370695
        let l:file = expand('%')
        let l:old_perm = getfperm(l:file)
        " set the exec bit everywhere the read bit is set
        let l:new_perm = substitute(l:old_perm, '\v(r.)-', '\1x', 'g')
        if (l:old_perm != l:new_perm)
            call setfperm(l:file, l:new_perm)
        endif
        unlet s:new_file
    endif
endfunction

augroup new_script_exec
        autocmd!
        autocmd BufNewFile * let s:new_file = 1
        autocmd BufWritePost * call NewScriptExec()
augroup END
0

I use this in MacVim Custom Version 8.0.648 (134)

" if file is executable just exit

au BufWritePost *.sh if FileExecutable("%") | if getline(1) =~ "^#!" | silent !chmod u+x % | endif | endif

" Determines if file is already executable 

function! FileExecutable(fname)

    execute "silent! ! test -x" a:fname
    return v:shell_error

endfunction
0

tonymac's answer stopped working for me at some point (with VIM 7.4), giving me the same problem as @StevieD. Modifying it fixed the problem:

au BufWritePost * if getline(1) =~ "^#!" | if getline(1) =~ "/bin/" | silent execute "!chmod +x <afile>" | endif | endif

I found the answer from https://bbs.archlinux.org/viewtopic.php?id=126304, although @StevieD also gave the same answer.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .