5

I am getting some unexpected behavior when trying to run the zip shell command using Vim's job_start().

As an example, suppose I have two images (im1.png and im2.jpg) in the directory /home/username/test_dir/ and I want to zip them. This shell command will zip the files:

cd /home/username/test_dir/ && zip ims.zip im1.png im2.jpg

Next, I make a simple vimrc file (/home/username/test_dir/simple_vimrc) containing only a function that runs that command via job_start():

function! Test()
    let job = job_start(['/bin/sh', '-c', 'cd /home/username/test_dir/ && zip ims.zip im1.png im2.jpg'])
endfunction

Then I open Vim as

vim --clean -u /home/username/test_dir/simple_vimrc

If I run :call Test(), the zip command does not seem to work - instead of producing a zip file it just produces an empty file with a random name. But here are some interesting observations:

  • Adding the job option {'err_io': 'buffer'} to the job_start() command makes it work. But it fails with all other 'err_io' options ('out', 'null', 'pipe', and 'file'). This seems strange because no error is produced anyway.

  • I added the job options 'out_cb', 'err_cb', 'close_cb', and 'exit_cb' to the job_start() command with blank callback functions (I tested each option individually). Strangely, all options except 'exit_cb' made the command work.

  • The command works if I run the let job = ... command directly in Vim's colon command line.

  • I tried all cases above by replacing the zip command with:

    • a pdflatex command to compile a simple Latex file (succeeded/failed in all the same cases as the zip command)
    • agcc command to compile a simple C file (succeeded in all cases)
    • a python command to run a simple Python file (succeeded in all cases)

I'm confused as to why job_start() successfully runs the command only in these certain cases. Is this expected behavior or a bug I should report?

5

I think I figured this out myself. I believe the problem was that my job was being deleted before the zip command finished. I guess Vim deletes a job object if there are no references to it. So the solution was to turn my job variable into a script-local variable to prevent it from being deleted. So, I changed my line let job = ... to let s:job = ....

I figured this out by reading through Vim's help pages:

:help job_start
...
                Note that the job object will be deleted if there are no
                references to it.  This closes the stdin and stderr, which may
                cause the job to fail with an error.  To avoid this keep a
                reference to the job.  Thus instead of:
        call job_start('my-command')
                use:
        let myjob = job_start('my-command')
                and unlet "myjob" once the job is not needed or is past the
                point where it would fail (e.g. when it prints a message on
                startup).  Keep in mind that variables local to a function
                will cease to exist if the function returns.  Use a
                script-local variable if needed:
        let s:myjob = job_start('my-command')
...
| 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.