充分利用VBScript

介绍

在一个没有任何编译器和Internet的Windows下,你发现你想批量处理(比如重命名)一堆文件,但Windows批处理可能做不了,Powershell太奇怪;你想操控Office,那么常规的脚本更是毫无用处;你想不停刷新浏览器来刷访问量(忘记没有Internet吧,当然网络基础好的可以直接发HTTP请求的请无视),你想留下一个有趣的恶意程序,常规的脚本似乎也不太容易实现。或许你懒得写C++,或者像我一样觉得用C++完成文件操作似乎大材小用,而且得不停的system。或许你不是OIer,只会VB6而不会正统的语言,VB6又显得很巨大。所有这些场景,都可能是VBScript大显身手的时机。它有如下优点:

  • 在现代的Windows(准确的讲是Windows 98 SE+即可)下无需任何额外程序即可运行,用记事本就可以写
  • 很接近VB6而不是VB.NET,理论上浙江的高中生都会(实际上是不存在的,毕竟有的人技术不怎么学)
  • 具有丰富的Windows Shell、文件系统的API,也能调用Office等外部程序的功能
  • 能在网页中实现类似JavaScript的功能,但很少有人用,而且只有IE支持(IE11已经砍掉了)

当然缺点也很多:

  • 调试不方便
  • 太古老了,不仅有安全性问题,而且有被微软砍掉的风险
  • 不跨平台,只在Windows下可用

快速入门

以一个真实的具体需求为例。有一堆有错误的音频文件(WMA,但这不重要),我们需要把每个文件截取前一半的时长,然后每四个文件拼接成一个新的长文件。拿到这个问题我感觉很棘手,因为每个文件的时长不一样,前一半需要计算才能得到,而ffmpeg并没有提供任何内置的计算功能。大概需要写脚本,用ffprobe获取时长,经过计算再用ffmpeg裁剪。真是麻烦!还好我突然发现GoldWave有批处理功能,只要执行设标、剪裁的批处理即可。

现在到了分组拼接的问题,这下GoldWave的批处理也没办法了,但这时写脚本要方便很多。如果你的ffmpeg基础较好,你应该知道用ffmpeg拼接WMA只有一种方法,即demux。这涉及创建一个文本文件,包含需要拼接的文件名列表,然后再调用ffmpeg。一开始我还是写了万年没写的C++:

groupconcat.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<cstdlib>
#include<cstdio>
#include<cstring>
using namespace std;
int main()
{
for(int i=20;i+3<=61;i+=4)
{
FILE *fout=fopen("list.txt","w");
for(int j=i;j<=i+3;j++)
fprintf(fout,"file '%03d.wma'\n",j);
fclose(fout);
char cmd[100];
sprintf(cmd,"ffmpeg -f concat -safe 0 -i list.txt -c copy %d.wma",i/4-4);
system(cmd);
//system("pause");
}
return 0;
}

解决问题后我想到很容易遇到没有GCC的情况,于是我努力用VBScript重写了一遍:

groupconcat.vbs
1
2
3
4
5
6
7
8
9
10
11
set fs=CreateObject("Scripting.FileSystemObject")
set sh=CreateObject("WScript.shell")
for i=20 to 56 step 4
set fout=fs.CreateTextFile("list.txt",true)
for j=i to i+3
fout.WriteLine("file '0"& j &".wma'")
next
fout.Close
sh.Run "ffmpeg.exe -f concat -safe 0 -i list.txt -c copy "& i/4-4 &".wma",0,true
next
msgbox "done"

可以发现和VB6有不少差异,比如赋值必须用setfor对应的next不需要写循环变量等等。

另一个例子是我以前用来刷Tabby Cat插件里的Goodies的,只要不停的刷新,就有一定概率出现新的玩意儿或者罕见的太空猫、彩虹猫。

refresh.vbs
1
2
3
4
5
6
set sh=createObject("wscript.shell")
wscript.sleep 2000
do while true
sh.sendKeys "{F5}"
wscript.sleep 100
loop

模拟按键输入还是很有用的。当然,为了终止这个脚本,你需要打开任务管理器,或者来一条taskkill /im wscript.exe /f。这在写恶意程序时显得更加重要。直接运行wscript.exe可以设置自动关闭脚本的时间。

在Windows 7+不要用古老的Ctrl+Alt+Del调出任务管理器,这样只会调出安全选项,再选任务管理器就慢了。请使用新快捷键Ctrl+Shift+Esc。这一点大部分人似乎都不知道。

附:我所知道的Ctrl+Alt+Del的历史演变

  • DOS时代:重启(其实在载入Windows前都可以这样重启,比如BCD菜单)
  • 早期的Windows:任务管理器
  • 早期的Windows服务器:登录时必须按,以确保登录界面不是虚假的(如果是假的大概会调出任务管理器,其实现在改一下注册表也能实现这种功能)
  • 现代的Windows:安全选项

建议的参考文献