5

I've been using vim recently to program in C. I have created shortcuts for compiling and running the programs from within vim itself, but recently vim's process has been stopping after executing the program.

foo.c:

#include <stdio.h>

int main() {
    printf("Hello World!\n");
    return 0;
}

.vimrc:

set shellcmdflag=-ic

syntax on

autocmd FileType c map <F6> :!gcc -o "%:p:r.out" "%:." <bar> more<CR>
autocmd FileType c map <F7> :!%:p:r.out<CR>

If I hit F6, the program compiles fine. But if I hit F7, I get the following:

Hello World!
[1]+  Stopped                 vim test.c

I can use fg to start the process back up, but it's getting slightly annoying to do so. Does anyone know how to fix this?

7

Don't use an interactive shell to execute commands. (That's the i in -ic.)

The default shellcmdflag (-c) should work just fine.

If you are specifying -i in order to get bash to read your .bashrc file (which is a side-effect of starting an interactive shell), then you would be better off just telling bash to read a startup environment script. Quoting the bash manpage:

When bash is started non-interactively, to run a shell script, for example, it looks for the variable BASH_ENV in the environment, expands its value if it appears there, and uses the expanded value as the name of a file to read and execute. Bash behaves as if the following command were executed:

          if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi

but the value of the PATH variable is not used to search for the file name.

You can set environment variables inside vim with :let

| improve this answer | |
  • Why does using an interactive shell cause this problem? The reason I was including -i was because I have gcc aliased in .bashrc. – Jeffrey Sep 17 '13 at 16:52
  • @Jeffrey: only one process group can own the terminal, and if you start an interactive shell, it will make itself its own process group. There are lots of details and variations depending on how all the various processes interact, but generally speaking you'll end up sending a signal to vim whose default action is STOP. I answered the implicit question (how to read .bashrc) in an edit to the answer. – rici Sep 17 '13 at 18:31
0

I agree that one should not use an interactive subshell, as rici points out in his answer. (I particularly appreciated the analysis of the problem in his comment.)

However, setting BASH_ENV is dangerous: if you do this you must make sure that Bash is never invoked from from that file, directly or indirectly, or you will end up in an infinite loop of spawning Bash processes. This can be difficult if you have a fairly sophisticated setup, since it's easy not to realize that a program you're calling is actually a Bash script.

My solution is simply to set shell=bash-rcc, which is the following script:

#!/usr/bin/env bash
#
#   bash-rcc - source ~/.bashrc and run bash -c command
#
#   This is used as the shell by programs such as vim where we want
#   `:!` commands to be able to use shell functions and aliases
#   defined in `~/.bashrc` but do not want the shell started in
#   interactive mode. Interactive mode does various things, such as
#   setting up its own process group, that can cause problems when
#   used to run a single command from another program.

[[ $1 = -c ]] && shift
. ~/.bashrc
eval "$1"
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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