6

I use vim's :! external command function all the time, usually providing % as an argument to the shell command. For example :

:!psql -f %

I also have a lot of bash shell functions in my .bashrc that I use. For example:

psql-h1 () 
{ 
    /usr/bin/psql -hh1 -d mydb "$@"
}

These bash functions aren't available from :! inside of vim. Is there a way to make them available?

Jeremy
  • 1,397
  • 2
  • 13
  • 20
  • Are you sure you're using `bash` from inside vim? Does running `:!echo $0` print `bash`? – hnefatl Oct 25 '17 at 17:54
  • Two solutions: 1. `:help 'shellcmdflag'`, 2. turn your function into actual scripts and put them somewhere in your `$PATH`. – romainl Oct 25 '17 at 18:01

4 Answers4

5

Export your functions. That is:

psql-h1() { /usr/bin/psql -hh1 -d mydb "$@"; }

export -f psql-h1  ### <-- THIS RIGHT HERE

This will make them available to any copy of bash run as a child process, even if it's a noninteractive shell and so doesn't read .bashrc.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • bingo. this right here. I knew you exported ENV variables to child processes. Had no idea about bash functions. – Jeremy Oct 26 '17 at 09:47
  • It's basically the same thing -- an exported function is just an exported variable with an unusual name and the function's code as a value; bash scans the environment for any names matching the convention and parses them as code. Double-edged sword, that feature -- it's what was responsible for shellshock. – Charles Duffy Oct 26 '17 at 15:28
3

An alternative to exporting your functions (which may no reach Vim is there's a non-Bash shell in between; see here for such a case), you can instruct Vim to start an interactive shell, so that your .bashrc is read. Just pass the -i flag to Bash, via Vim's :help 'shellcmdflag'.

:set shcf=-ic
Ingo Karkat
  • 167,457
  • 16
  • 250
  • 324
0

This answer assumes your vim isn't actually using bash to invoke the remote commands - this can be tested by running :!echo $0 in vim.

Specifically for vim, add:

set shell=/bin/bash

to your .vimrc.


In general, there's two strategies I've found to sometimes work when trying to get other programs to invoke my preferred shell:

export SHELL=/bin/bash

in eg. the .profile file, or:

ln -fsn /bin/bash /bin/sh

which updates the sh symlink to point to bash instead.

On many systems (certainly Ubuntu), /bin/sh is a symlink to a sh-compatible shell (such as bash), rather than the sh shell itself. Given this fact, some programs (I've seen this behaviour in GHC) seem to invoke /bin/sh, so changing where it points to will cause the programs to use bash instead.

hnefatl
  • 5,860
  • 2
  • 27
  • 49
  • Ensuring that the shell is bash is necessary, but not sufficient: Copies of bash that don't have the interactive flag (that is, those where `[[ $- = *i* ]]` is not true) don't read `.bashrc`. – Charles Duffy Oct 25 '17 at 18:20
  • Also, making `/bin/sh` a link to bash doesn't mean you get bash syntax when it's invoked -- the bash executable runs in POSIX compatibility mode when invoked under that name. Some extensions still work in that mode, but by no means all of them. – Charles Duffy Oct 26 '17 at 12:10
0

The accepted answer didn't work for me. I'm going to go with setting shcf, as suggested elsewhere:

:set shcf=-ic

but another solutions is

!source ~/.bashrc && psql ...

Unfortunately, no solution allows the auto-completion for the command I'm creating to work properly. (The auto_completions suggested are for names of files in my current directory, rather than the ones I specified as follows in .bashrc

complete -F _generate_foo_completions foo
Leonard
  • 13,269
  • 9
  • 45
  • 72
  • If the accepted answer didn't work, the first place I'd start looking in debugging is whether vim is starting the same shell release you did the `export` from pre-invocation. Pre- and post-shellshock versions of bash use different formats for storing exported functions in the environment, and if one shell isn't bash at all but is zsh or something else, well, there's your issue. – Charles Duffy Mar 31 '19 at 18:15
  • ...if the `source` command works at all, that tells us vim isn't starting `/bin/sh` (at least, not on a platform where `/bin/sh` is provided by dash or another non-bash shell), but unfortunately, "doesn't work" isn't a lot of details to debug from. – Charles Duffy Mar 31 '19 at 18:16
  • (Whether the environment is having variables with nonconformant names cleaned up by an intermediate process is another place to look; [Ingo's link](https://stackoverflow.com/questions/38079864/regression-exported-bash-function-lost-after-going-through-another-process) goes into some detail). – Charles Duffy Mar 31 '19 at 18:17