最开始的时候, 同学在工作中需要为服务器安装软件, 但多台服务器的重复工作让他想寻找一种自动化的方式, 于是拜托我找一找. 但这方面我没有研究, 随便找了下, 也就是基于打包软件的命令行安装, 以及类似AutoHotKey 这样的自动化软件. 如果没听过AutoHotKey, 你可以理解为按键精灵之类的.
第一种方式, 由于安装文件的打包软件有很多种, 像Nullsoft 、InstallShield ,Advanced Installer 等, 我自己没有开发过像样的Windows程序, 这方面不了解. 查资料的结果是不同打包形式需要不同的命令和参数, 有得似乎并不提供静默安装的方式. 另外, 得针对不同软件, 辨别打包形式, 也挺麻烦. 至于第二种, 熟悉Linux平台的应该都习惯于使用脚本做一些自动化操作. 这里的脚本包括shell , python , ruby 等. 所以, 基于学习另一种语言的想法, 便看了AutoHotKey 的初学指南. 注意: 此处并不是原文翻译, 只是自学笔记和感受, 主观成份很多.
AutoHotKey (以下简称AHK )是Windows 平台下一款免费开源的自动化软件, 方便用户处理重复性的任务. 它是一种脚本语言, 最开始只用于定义热键(hotkey )和相应的动作.
快速开始 在官网https:/// 下载软件并安装. 任意目录右击新建Autohotkey script , 追加^w::MsgBox, hello, world 文本, 保存并双击脚本运行. 在任务栏右下脚会出现AutoHotKey 的运行图标. 此时, 按键Ctrl+w 会弹出对话框, 显示hello, world , 说明软件工作正常. 追加文本有这样的形式, hotkey::action . 此处, ^ 表示Ctrl 键, 如果一定要区别左右, 可以使用<^ 和>^ 的形式. 还有! 表示Alt 键, # 表示Win 键, + 表示Shift 键, 且都可以使用<> 前缀表示左右键. ^w 表示快捷键Ctrl+w , ^!w 表示快捷键Ctrl+Alt+w , 依此类推. 而动作部分是一个命令MsgBox , 表示弹出对话框, 并显示文本. 可以有更多的参数, 以自定义标题栏文本, 选择按钮(如yes/no/cancel 还是drop/save/ignore ). 所谓的组合键, 字面意思是同时按下多个键, 但如果你的多个键都是正常键, 即没有`Ctrl`, `Alt`, `Shift`, `Win`键的话, 需要`&`来组合. 如同时按`a`和`b`, 表示为`a & b`. 另外, 如果热键只有`Ctrl`单键, 则需要用`Ctrl`来表示, 左右为`LCtrl`和`RCtrl`, 不区分大小写. 其余键类同. 此处, 因为动作只有一个, 因此写到:: 后即可, 多个动作从第二行起, 每行一个动作, 最后写上Return 表示此热键定义的动作完毕, 下面的内容属于另一个热键的. 除了定义热键外, AHK 另一个常用法是文本替换, 或者说热字串(hotstring ). 如::hw::hello, world . 重载入后, 在任意输入框, 包括所有的文本编辑器, 浏览器地址栏, 百度搜索框等, 当键入hw 后, 任意结束符EndChar 都会触发文本替换. 此处的结束符, 可能理解为非数字字母. 本质上, 当键入结束符, 由AHK 发出退格键N次再键入入替换文本. 注意, 每添加一个新的热键或热字串, 都需要重新载入脚本. 可在右下脚的运行图标上右击, 选择Reload this script . 或者可以自定义热键来重载入脚本. hotkey::action ;1, 单行定义 hotkey:: ;2, 多行定义 action1 action2 ...Return ::hotstring::text ;3, 热字串, 文本替换 ::hotstring:: ;4, 热字串, 动作触发 action Return
虽然我这里区分了大小写, 但事实上AHK 并不区分大小写, 但仍然推荐驼峰写法以方便辨认. 通过这种方式定义的热键或热字串都是全局性的, 如果想定义针对特定窗口的热键或热字串, 可以用如下形式 #IfWinActive Untiled - Notepad ;标题栏文本#space:: MsgBox You pressed Win+Spacebar in notepad.Return#IfWinActive
此处在无标题记事本中创建了热键Win+space . AHK 还提供了简单的条件语句
if (var = 5) { ; equal? msgbox, var equals %var%} else { MsgBox, var not equals %var%}
以上4种形式, 就基本是AHK 的主要内容了. 分点细讲 AHK 最主要的部分是热键, 函数, 和命令. 热键方面, 要知道你想要的热键如何表示. 函数和命令则是需要查表和记忆. 其余还有变量, 各种语句等.
函数和命令是AHK 最奇怪的部分. 命令没有返回值, 函数有; 命令行参数文本默认为字串, 函数参数的字串必须' 包围; 命令参数不能嵌套命令, 而函数参数可以是另一个函数的返回值; 命令参数文本中的+!#^ 被解析为特殊热键, 需要{} 包围来表示原符号, 而函数参数中的字串不需要; 命令的参数中变量以% 包围, 函数不需要; 命令参数中数学表达式并不运算, 函数会. 以上的不同, 并不是针对函数和命令的参数, 在其他方面也适用. 我一般将命令参数表现出来的特性理解成文本 , 而函数参数表现出来的特性理解成表达式 . 以下会提到在赋值语句中的差异. 其实在条件语句中, 当有() 时, 适用表达式, 而没有() 时, 适用文本. 但即使在文本中, 也只有在操作符如=<> 右边才需要% 包围变量. 这些差异大部分时候让我觉得很奇怪, 不明白语言为什么如此设计. 我相信这对任何一个学习过通用编程语言的人来说, 都是不可接受的. 但考虑到AHK 其实并不是作为脚本语言被精心设计, 而是在autoit 软件的基础上扩展起来的. 这是自己的理解, 我对AHK 的历史以及开发记录并不了解. 变量 使用变量并不需要类型声明, 这点类似动态语言. var = textvar := expression
上面说的文本和表达式的差异在此处也适用. 如num = 5*3 , 实际上, num 并不是15 , 而是字串5*3 . 此处数学表达式不运算, 而:= 则会. 另外, var1=var2 并不是将var2 的内容给var1 , 而是将字串var2 给var1 . 需要var1=%var2% 来达到目的. 而var1:=var2 则可以. 其实差异还是挺多的, 所以我一直认为这里的语法设计的太冗余了. 建议大家可以的话, 尽量使用:= . 命令 因为命令比较经常使用, 先介绍经常使用的命令. 再声明一遍, 命令名不区分大小写. cmd, arg1[, arg2, arg3...] , 这是命令的一般形式, [] 内的参数表示可以省略. 如果只想省略中间的某个参数, 用,, 连续两个, 来将此位置的参数空过.
注意上面提到的, 在命令参数中, 有特殊的注意事项. 参数使用变量用% 包围, 文本和数字无需' 包围, 参数不进行数字运算. 一行一条命令. Send, text : 发送文本, 本质上是发送敲击的键. 对于数字字母就是对应的符号, 而+!#^ 则是对应的热键, 请以{} 包围. 另外, 还有些特殊键, 如回车{enter} , 删除{del} , 大写{CapsLock} 等.
Run, program : 运行程序, AHK 会在%path% 中查找. 如Run, NotePad.exe , 其中后缀可省略. 除了程序, 也可以直接打开网页run, www.baidu.com 会调用默认浏览器打开百度首页. 也可以打开目录, 如run, %A_MyDocuments 将打开我的文档 . 此处的%A_MyDocuments 是AHK 预定义变量.
WinActivate, title_text : 激活指定标题栏的窗口, 注意操作系统环境不同, 标题栏文本的语言也不同. 如打开记事本, 在英文环境下, 标题栏文本是Untitled - notepad , 中文环境下是无标题 - 记事本 . 我想, 这里是AHK 唯一区分大小写的地方了吧.
WinWaitActive, title_text : 等待指定窗口的激活, 往往同上一起使用, 以确保接下来的命令运行在正确的窗口中.
sleep, num , 停止毫秒
MsgBox, text : 显示对话窗口, 跟文本参数, 只有确定 按键.
MsgBox [, options, title, text, timeout] : 单独一个msgbox 会提示press ok to continue , 选项显示不同的按钮, 如4yes/no 或1ok/cancel ,2abort/retry/ignore ,3yes/no/cancel 等.
InputBox, output_var, title_text, question_text , 以窗口形式获取用户输入
IfMsgBox, Yes/No : 如果对话框点击确定或否, 或者依据选项的不同输入, 来决定下一步
函数 函数一般有这样的形式, var:=func(arg1, arg2, ...) . 变量直接用, 字串以' 包围, 参数进行数字运算, 函数可嵌套, 有返回值. SubStr(string, num) , 返回从num位置的字串, 1索引
FileExist(path) , 文件存在判断
特殊按键 {f1}-{f12}
{enter/space/esc/tab}
{bs/del/ins}
{up/down/left/right}
{home/end/pgup/pgdn}
{capslock/scrolllock/numlock}
{ctrl/lctrl/rctrl down/up} , alt , shift , win 同
{+!^#{}} , 仅表示+ , ! , ^ , # , { , }
{numpad0-9} , {numpaddot/enter/mult/div/add/sub} 数字键盘的键, 按下numlock 键时
{numpadup/down/left/right/home/end/pgup/pgdn/del/ins/clear} 数字键盘的控制键, numlock 未按下时
{browser_back/forward/refresh/stop/search/favorites/home} , 浏览器的按键
{volume_mute/down/up 音量键
{media_next/prev/stop/play_pause} 媒体控制键
预定义变量 以% 包围, 如%A_WorkingDir% . 脚本属性: 1, 2, 3 , 脚本的命令行参数, 0 表示参数数目
A_ScriptDir, A_ScriptName, A_ScriptFullPath, A_ScriptHwnd 运行脚本的目录,文件名,全路径,主窗口句柄.
A_LineFile, A_LineNumber, A_ThisFunc, A_ThisLabel 表示当前运行命令的文件,行号,函数,标号, 用于错误处理
A_AhkVersion, A_AhkPath 本程序的版本和路径
A_IsUnicode, A_IsCompiled, A_ExitReason 是否是unicode, 是否编译, 退出原因
对象创建对象: (数组或列表, 字典或哈希, 在不同语言中叫法不同) MyObject := ['one', 'two', 'three', 17] ; 字面量创建 banana := {'Shape': 'Elongated', 'Color': 'Yellow'} MyObject := Array('one', 'two', 'three', 17) ; 函数创建 Banana := Object('Shape', 'Elongated', 'Color', 'Yellow')
添加新元素或改变原键值: Banana.Consistency := 'Mushy' Banana['Pickled'] := True ;两种方式索引, `.`和`[]`操作符 MyObject.NewKey := 'Shiny' ;给数组添加键值对 MyObject.InsertAt(Index, Value1, Value2, Value3, ...) ;多元素插入 MyObject.Push(Value1, Value2, Value3, ...) ;追加元素
移除键值: MyObject.NewKey := '' ; 移除值 RemovedValue := MyObject.Delete(AnyKey) ; 移除键 NumberOfRemovedKeys := MyObject.Delete(FirstKey, LastKey) MyObject.Pop() ; 弹出尾元素 RemovedValue := MyObject.RemoveAt(Index) ; 移除索引处键 NumberOfRemovedKeys := MyObject.RemoveAt(Index, Length)
这里需要说明的是, Array 和Object 是相同的对象, 数组默认的数字索引, 但也可以添加键值对. 则之前的值通过1,2,3 索引, 加入的值通过键索引. 对于数组, 第一个元素的索引为1. 另外, 在命令中, 默认的是文本, 似乎不能直接输出MyObject.NewKey , 无论是否以% 包围. 变通的方法是赋值给变量, 再将变量以% 输出.
|