39

I don't like how Vim clutters up my folders with backup files, so I have the following line in my .vimrc file:

set backupdir=~/.vim_backup

However, sometimes this folder doesn't exist because of new machines where I am copying my user files over.

How can I create this folder automatically if it doesn't exist, from within .vimrc? Or is there some better way to deal with this situation?

1
  • vim has the builtin function isdirectory(your_path). Also you could have vim delegate to the shell: let directory_exists = system("test -d $YOURDIR; echo $?"). As with all issues of files/directories, Watchout for hard/soft symbolic links, mounted drives, race conditions and read permissions. Commented Jul 22, 2018 at 2:13

8 Answers 8

99

I think this is operating system independent:

if !isdirectory("/my/directory")
    call mkdir("/my/directory", "p")
endif
2
  • 19
    but in that case you have to use $HOME instead of ~ silent !mkdir ~/.vim_backup > /dev/null 2>&1 will become silent call mkdir ($HOME.'/.vim_backup', 'p')
    – m42e
    Commented Jun 6, 2014 at 8:53
  • As m42e says, mkdir("~/directory", "p") will make one dir \~/directory dir in the current dir more specifically. The main problem is that ~ is interpreted literally in quotes by vim.
    – An5Drama
    Commented Apr 10 at 2:09
35

You can put this into your .vimrc:

silent !mkdir ~/.vim_backup > /dev/null 2>&1

This will attempt to create the ~/.vim_backup each time you start vim. If it already exists, mkdir will signal an error, but you'll never see it.

8
  • 11
    +1: Good answer. Assuming Linux, you could also do !mkdir -p ~/.vim_backup as the -p option will stop mkdir reporting an error in the first place (as well as making parent directories if required).
    – DrAl
    Commented Oct 11, 2009 at 15:18
  • 11
    Why do you do !mkdir? There is built-in vim function mkdir() which serves same purpose and is more portable. More, your code without surrounding if is doing an unnecessary shell call which slows down startup.
    – ZyX
    Commented Dec 11, 2011 at 7:38
  • @ZyX yeah, so the question is: how do you detect whether a folder exists? I know filereadable(), is there an equivalent for folders? Commented May 19, 2012 at 12:50
  • 1
    EDIT: I have just RTFM, there is isdirectory(). Will edit the answer soon. Commented May 19, 2012 at 12:55
  • 1
    @barraponto You don’t need to check, whether path is a directory, you need to check whether it exists. This is a different construct: empty(glob('~/.vim_backup')). It will catch the cases “path is a directory” (also caught by isdirectory(), “path is a readable file” (also caught by filereadable()) and also “path is unreadable file” (caught by nothing else). In all three cases mkdir() will fail.
    – ZyX
    Commented May 19, 2012 at 15:36
13

You could use the mkdir() Vim function. It can create intermediate directories and set proper permissions on the directory as well:

if !isdirectory($HOME . "/.vim/backup")
    call mkdir($HOME . "/.vim/backup", "p", 0700)
endif
1
  • Just curious... I tried this solution, but ~/.vim/somepath/ doesn't quite work as it works the full path instead of the ~. Anyway, once I figured that, it worked as a charm.
    – DrBeco
    Commented Jul 8, 2017 at 7:38
11

I much prefer the one-liners already posted. However, I thought I'd share what I've been using:

function! EnsureDirExists (dir)
  if !isdirectory(a:dir)
    if exists("*mkdir")
      call mkdir(a:dir,'p')
      echo "Created directory: " . a:dir
    else
      echo "Please create directory: " . a:dir
    endif
  endif
endfunction

call EnsureDirExists($HOME . '/.vim_backup')
1
  • The "Created" message could be false if mkdir throws an error.
    – Tom Hale
    Commented Sep 27, 2016 at 8:17
2

I wanted a solution to this that works on both Linux and on Windows (with Cygwin binaries on the path.) - my Vim config is shared between the two.

One problem is that 'mkdir' is, I think, built-in to the cmd shell on windows, so it can't be overridden by putting the Cygwin mkdir executable earlier in the path.

I solved this by invoking a new bash shell to perform the action: From there, 'mkdir' always means whatever mkdir executable is on the path:

!bash -c "mkdir -p ~/.vim-tmp"

However, this has the problem that. on Windows at least, it pops up a new window for the cmd shell that '!' invokes. Don't want that every time I start vim. Then I discovered the vim function 'system', which invokes a new cmd shell (the icon appears in the Windows taskbar) but the window is minimised. Hence:

call system("bash -c \"mkdir -p ~/.vim-tmp\"")

Ugly but works.

1
  • Look at @xer0x answer, you can check if the directory exists and only then call system, making your solution ugly but as practical as possible on a window host. Commented May 19, 2012 at 15:26
1

I have a command in my vimrc that enables me to make a directory corresponding to the buffer presently frontmost:

nmap <silent> ,md :!mkdir -p %:p:h<CR>

This can be used to create a directory any place you care to put one locally or remotely via netrw if you the permissions to do so.

2
  • 1
    Hey. What precisely does 'corresponding to' mean? Not 'named the same as', that doesn't quite make sense to me. So what? Commented May 21, 2012 at 12:04
  • You can find out by doing :!echo %:p:h. It's basically the path for the file of the buffer that's currently "active" (Very late to the party, but adding none the less ^-^)
    – imme
    Commented Jan 15, 2020 at 9:20
0

This is built into Vim, so you can simply:

call mkdir($HOME . "/tmp")

You can also specify the p flag to have the command operate in the same way mkdir -p would:

call mkdir($HOME . "/tmp", "p")

For details see :help mkdir or the vim manual online.

0

This is what I am currently using in my .vimrc file and I think it looks quite clean and simple:

if empty(glob($HOME . '/.vim/undodir'))
  call mkdir($HOME . '/.vim/undodir', 'p')
endif

Not the answer you're looking for? Browse other questions tagged or ask your own question.