从Vim调用脚本启动Zathura显示空文件的问题排查
问题描述
我编写了名为md的shell脚本:
#!/bin/sh if [ -z $1 ]; then echo "Error: No argument supplied" else (pandoc -t pdf $1 | zathura - &) fi
该脚本在终端运行正常,执行md foo.md可通过Zathura打开生成的PDF。但在Vim的init.vim中添加自定义命令command Md ! md %:p后,执行:Md时Zathura虽启动却显示空文件(底部标注"[No name]")。直接复制Vim输出的命令到终端执行,Zathura却能正常显示文件。请问该问题的原因是什么?
原因分析
核心问题出在Vim对外部命令I/O流的管理逻辑:
当你在Vim里执行:Md时,Vim会启动md脚本作为自己的子进程,并且会接管这个子进程的所有I/O资源。你的脚本里用了(pandoc -t pdf $1 | zathura - &),把pandoc的输出通过管道传给后台运行的zathura,但脚本本身执行完就会立即退出——此时Vim会直接关闭该子进程关联的所有文件描述符,包括pandoc输出到zathura的管道。
zathura还没来得及完整读取pandoc生成的PDF数据,管道就被切断了,自然只能显示空文件。而在终端直接执行脚本时,后台进程的I/O流和终端会话绑定,脚本退出后管道不会被立即关闭,pandoc可以把完整的PDF数据传给zathura,所以能正常显示。
解决方案
方案1:用临时文件替代管道
避开管道被提前关闭的问题,先让pandoc生成临时PDF文件,再用zathura打开:
#!/bin/sh if [ -z "$1" ]; then echo "Error: No argument supplied" >&2 else temp_pdf=$(mktemp --suffix=.pdf) pandoc -t pdf "$1" -o "$temp_pdf" && zathura "$temp_pdf" & # 可选:zathura退出后自动删除临时文件 trap 'rm -f "$temp_pdf"' EXIT fi
方案2:让进程脱离Vim的I/O控制
用nohup让zathura完全脱离当前会话的I/O绑定,避免Vim关闭管道:
#!/bin/sh if [ -z "$1" ]; then echo "Error: No argument supplied" >&2 else nohup sh -c 'pandoc -t pdf "$1" | zathura -' "$0" "$1" >/dev/null 2>&1 & fi
方案3:修改Vim命令
让Vim把外部命令放到后台执行,不等待其结束,这样不会过早关闭I/O流:
command Md ! md %:p &
内容的提问来源于stack exchange,提问作者Peatherfed
相关产品推荐
相关产品推荐

