从diff输出启动vimdiff的Shell脚本执行问题求助
解决通过Shell脚本批量启动vimdiff对比文件夹差异的问题
我来帮你搞定这个问题!你遇到的几个问题其实都和终端交互以及命令执行的环境有关,下面逐个分析并给出解决方案:
为什么之前的方法不行?
- 管道传给bash出现警告:当你用
... | bash时,bash的标准输入是管道,而vimdiff是交互式程序,它需要连接到真实终端才能正常运行,所以会抛出Vim: Warning: Input is not from a terminal的警告,甚至可能无法正常操作。 - bash -c报错:你应该是直接写了
... | bash -c,但bash -c需要接收一个字符串作为要执行的命令参数,而不是从标准输入读取,所以会提示option requires an argument。 - 命令替换无输出:
$(...)是在子shell中执行命令,子shell的终端环境和当前主shell不一致,交互式的vimdiff无法在子shell中正常显示界面,所以看起来没有输出。
可行的解决方案
方案1:用xargs逐个启动vimdiff
这是最简洁的方法,xargs会把每行的两个文件名作为参数传给vimdiff,并且保证每个vimdiff都连接到当前终端:
diff -Bbqr oldfolder newfolder | grep differ | awk '{print $2, $4}' | xargs -n2 vimdiff
-n2表示每次取2个参数(正好对应每个文件对),执行一次vimdiff;- 关闭当前
vimdiff窗口后,会自动打开下一个差异文件的对比窗口。
方案2:用while循环逐行执行命令
这种方式更直观,手动读取每个生成的vimdiff命令并在当前shell环境下执行,完全避免终端关联问题:
diff -Bbqr oldfolder newfolder | grep differ | awk '{print "vimdiff " $2 " " $4}' | while read -r cmd; do $cmd done
read -r用来读取每行命令,避免特殊字符被转义;- 同样,关闭一个
vimdiff后才会执行下一个。
方案3:正确使用bash -c
如果你坚持想用bash -c,需要把生成的所有命令作为一个整体字符串传递给它,而不是通过管道输入:
bash -c "$(diff -Bbqr oldfolder newfolder | grep differ | awk '{print "vimdiff " $2 " " $4}')"
$(...)会把所有vimdiff命令拼接成一个字符串,作为bash -c的参数;- 这个方式也能让
vimdiff连接到当前终端,逐个执行命令。
额外小提示
如果你的文件名包含空格或特殊字符,上面的awk处理会出问题,这时候可以改用diff的格式化参数来更安全地提取文件对,比如:
diff -Bbqr --unchanged-group-format= --changed-group-format='%F %f\n' oldfolder newfolder | xargs -n2 vimdiff
这个方法不需要grep和awk,直接让diff输出需要对比的文件路径,更健壮。
内容的提问来源于stack exchange,提问作者Jim
相关产品推荐
相关产品推荐

