15

Environment: debian9+vim7.4.

   cat .bashrc
   add(){
        echo $(expr $1 + $2)
    }

Now edit a file in vim

add 1 5 

Run it in command mode :w !bash,an error occur.

bash: line 1: add: command not found    
shell returned 127

1.add set shellcmdflag=-ic in both /etc/vim/vimrc and .bashrc and .vimrc .
2.reboot
3.vim test.sh
enter into command mode
:verbose set shellcmdflag

  shellcmdflag=-ic
        Last set from ~/.vimrc

4.input two lines in test.sh

ls
add  5  6

:w !bash     
a1.sh       test.py    
bash: line 2: add: command not found    
shell returned 127    

How to make both two lines executed? enter image description here
enter image description here

:execute '! source ~/.bashrc; source '.expand('%:p') can make both commands: ls and add run.

After rebooting,
1.add function can't be called from sh test.sh?

sh test.sh
test.sh   #it means that ls command executed
test.sh: 2: test.sh: add: not found  #it means that add function can't be called from  /etc/vim/vimrc or .bashrc  or .vimrc.

2.add function can't be called from vim !bash %?

enter image description here

test.sh    #it means that ls command executed
test.sh: line 2: add: command not found  #it means that add function can't be called from  /etc/vim/vimrc or .bashrc  or .vimrc.

[4]+  Stopped                 vim test.sh
  • Perhaps you forgot to source your .bashrc? After any modification you have to run `source ~/.bashrc`, changes will be visible only in that console or all consoles after a reboot. – LMC Feb 06 '18 at 13:17
  • try to add `echo bashrc running` in your .bashrc file. When you open a new terminal, do you see "bashrc running" printed in your screen? When you run `:!...` in vim, do you do you see "bashrc running" printed in your screen? – sudavid4 Mar 05 '18 at 23:34

5 Answers5

16

The problem is that Vim by default invokes a non-interactive shell, and .bashrc (where you've defined your add function) is only read for interactive shells.

You can instruct Vim to use an interactive shell:

:set shellcmdflag=-ic

This may make external command invocations slighly slower (due to the overhead in evaluating your Bash initializations).

Alternatively, you could define the function somewhere else, so it's always available (but there's no easy place like this; see man bash, esp. the INVOCATION section). Or turn the function into a separate script accessible from your PATH (e.g. ~/bin/add).

Ingo Karkat
  • 167,457
  • 16
  • 250
  • 324
  • Why add `set shellcmdflag=-ic` in /etc/vim/vimrc can't work? –  Feb 06 '18 at 13:39
  • Is it overridden later? Check with `:verbose set shellcmdflag?` In general, you should prefer user-configuration (`~/.vimrc`) over system-wide one; are you sure that `/etc/vim/vimrc` isn't overwritten when you update your system / Vim? – Ingo Karkat Feb 06 '18 at 14:38
5

The problem is your function is limited to an interactive shell to execute it you have to do like this

:!bash -ic "add 1 2"
exe
  • 107
  • 6
4

To add the line export -f add in .bashrc file.

   add(){
        echo $(expr $1 + $2)
    }
    export -f add

Now source .bashrc,every method can call add function from .bashrc properly.

showkey
  • 482
  • 42
  • 140
  • 295
  • (see also [Exporting a function in shell](https://stackoverflow.com/questions/1885871/exporting-a-function-in-shell)) – user202729 May 09 '19 at 09:47
1

I suppose this should solve it for you. It's more of a workaround than an explanation of you problem but it gets the job done

:execute '! source ~/.bashrc; source '.expand('%:p')

I'm just manually sourcing bashrc before calling the command. One possible explanation to your problem is if you are on a mac. As far as I know OSX don't source bashrc, they do source bash_profile though.

sudavid4
  • 1,081
  • 6
  • 14
  • `:execute '! source ~/.bashrc; source '.expand('%:p')` can make it run,why other methods can't call add function properly? –  Mar 05 '18 at 23:16
  • the other answers are assuming that whenever you run your shell interactively your `~/.bashrc` will be sourced. It's a reasonable assumption, I don't know why it wouldn't. What we are doing here is explicitly sourcing this file. I wouldn't run my shell command interactively if I know that I don't need it. As having `.bashrc` sourced is all you need I suggested using this piece of code. – sudavid4 Mar 05 '18 at 23:25
1

How to make both two lines be executed?

 ls
 add 5 6    

This also works (with either shellcmdflag=-ic or shellcmdflag=-c) :

:w !bash -i

With this approach there is no need to include export -f add in .bashrc.

Why add function can't be called from vim with !bash %?

Assuming you have flags shellcmdflag=-c you can do:

:!bash -i ./%

which is quite similar to the answer of exe.

builder-7000
  • 7,131
  • 3
  • 19
  • 43