9

In vi, I can get a shell terminal with :sh command. And later, I can return to vi by exit shell.

But, if I was using the shell terminal for a long time, and I forgot whether exit will close anything or return me the vi.

Is there any way to check whether I will return to vi? jobs or fg is not working.

hailinzeng
  • 197
  • 2
  • 5
  • 3
    I stopped using the :sh command many years ago due to issues with the separate shell that Vim starts and the inability to return to it. Instead, I started putting Vim in the background (ctrl-z) to get back to the normal shell. Getting back to Vim from the normal shell is easy using the bash job control functions. – bsnyder May 04 '17 at 21:51

3 Answers3

8

In a regular shell:

$ env | grep -i vim
EDITOR=vim

After using :shell

$ env | grep -i vim
EDITOR=vim
VIMRUNTIME=/usr/share/vim/vim80
VIM=/usr/share/vim
MYVIMRC=/home/martin/.vim/vimrc

So it looks like Vim sets the VIMRUNTIME, VIM, and MYVIMRC environment variables. Of those, VIM seems the most reliable to me (you may not have a vimrc or even vim runtime).

You can also set your own environment variables:

:let $HELLO = "test"
:shell
$ echo $HELLO
test

This is especially useful to communicate info about the buffer you're editing; for example:

:let $VIM_FILETYPE = &filetype
:let $VIM_FILENAME = expand('%:p')

Will show up as something like:

VIM_FILETYPE=go
VIM_FILENAME=/home/martin/a.go
Martin Tournoij
  • 62,054
  • 25
  • 192
  • 271
3

I have my command prompt set up to add a red "+" symbol that indicates if I am in a vim ":sh" as opposed to a normal shell session. The cornerstone of it is that "$$" is the pid of the current process so:

MY_PPID=$(ps --no-header -o ppid -p $$)          # Gets the pid of the parent
                                                 # process.
MY_PCMDLINE=$(ps --no-header -o cmd -p $MY_PPID) # Gets its command line.
MY_CMDDASH=$(awk '{print $1}' <<<$MY_PCMDLINE)   # Gets the command name, possibly
                                                 # with a preceding hyphen.
MY_CMD=${MY_CMDDASH#-}                           # Get the bare command name.

Once you have this you can easily inline and construct something like I described to use in your ".bashrc" or similar.

Note: The environment variable ($VIM) method described elsewhere seems better than this but I'll leave this as it works in identifying if you are a child process of anything (not just vim).

chalkwalk
  • 3
  • 2
Dan
  • 31
  • 1
  • 1
    Vim puts three variables into the environment of the shell it lauches with :sh: MYVIMRC, VIM and VIMRUNTIME. All you have to do to know you're running in a sub-shell of Vim is to test for the presence of any of those. – garyjohn May 05 '17 at 00:04
2

Execute ps, or better, ps -fH. Ex:

$ ps -fH
UID        PID  PPID  C STIME TTY          TIME CMD
garyjohn 31140 31139  0 10:26 pts/11   00:00:00 bash
garyjohn 31267 31140  2 10:26 pts/11   00:00:00   vim hello.txt
garyjohn 31271 31267  0 10:26 pts/11   00:00:00     /bin/bash
garyjohn 31332 31271  0 10:26 pts/11   00:00:00       ps -fH

The advantage to using ps -fH over just ps is that it lets you see whether you are in a sub-shell of vim or if you put vim in the background. In that case, ps -fH would look like this:

$ ps -fH
UID        PID  PPID  C STIME TTY          TIME CMD
garyjohn 31140 31139  0 10:26 pts/11   00:00:00 bash
garyjohn 31267 31140  0 10:26 pts/11   00:00:00   vim hello.txt
garyjohn 31924 31140  0 10:29 pts/11   00:00:00   ps -fH
garyjohn
  • 6,309
  • 20
  • 21