前言
Directory Opus 与外部工具集成,大方向无非就两种:由外部工具调用 Directory Opus 和 通过 Directory Opus 调用外部的工具。
外部工具调用 Directory Opus
Directory Opus 提供了一个二进制程序 dopusrt,位于软件的根目录。可以通这个程序,在外部调用命令和操作 DOpus。
比如在 CMD 或 PowerShell 中运行以下命令,将使用 DOpus 的查找功能在 C:\Users 中查找文件名中包含 cat 或 dog 的文件。
& 'C:\Program Files\GPSoftware\Directory Opus\dopusrt.exe' /acmd Find NAME="cat dog" IN C:\Users ANYWORD
效果相当于直接在 DOpus 中执行内部命令:
Find NAME="cat dog" IN C:\Users ANYWORD
但是说实话,我目前并没有遇到什么实际场景需要从外部调用 DOpus 的。
像上面的文件搜索,我一般直接用 Listary 这种启动器就能完成了,并且本身就与 DOpus 有一定程度的集成。完全没必要走外部命令调用的形式...况且 DOpus 本身的查找功能相当的慢,远不如索引好的启动器或 Everything 搜索的快。除非你是想要查找 DOpus标签之类只能用 DOpus 查找面板搜索的数据,不然还不如直接用启动器查找。
总而言之,这个方向对我来说有点别扭,甚至是负效率。不想为了集成而硬使用功能,因此没有进行过多的探究。
不过有过一种想法,就是和 通过 Directory Opus 调用外部工具 结合起来,将脚本的功能实现完全外置,在外置脚本中调用 内部命令 等功能。
通过 Directory Opus 调用外部工具
在 DOpus 中调用外部工具或脚本,是我最常用的集成方式。
DOpus 本身是支持自定义脚本的,但是由于设计和历史原因,Opus 使用 JSCript 和 VBScript 作为脚本语言。JScript 不同于现在 Web浏览器 或 Node.js 中使用的 JavaScript,语法和特性都是相当的古老(差不多相当于 ES3 吧...),并且没有现代工具链的支持,写脚本的体验是相当的难受(特别是对于喜欢用现代 JS 特性的人来说)。
虽然现在有 AI 加持,但是实际上 AI 生成的结果往往也不是很理想。并且官方也没有打算引入新的脚本语言。
因此对于一些稍微复杂的脚本需求,我往往会选择通过调用外置脚本/工具的方式来实现。
对于喜欢用 DOpus 此类效率工具的人来说,电脑上基本上也有会 Python 或 Node.js 环境,因此我喜欢用 Python 或 JavaScript 来作为外部的脚本语言。
当然,比较简单或对 DOpus 依赖性比较强的脚本(调用 DOpus 命令等),我还是会用 DOpus 本身的脚本模块来完成。
说了这么多,这个方向的集成,实际上就是利用 DOpus 的界面,将当前选中文件、路径、对话框输入内容等作为参数,传递给脚本。
为了更好的集成,以及配置导入导出迁移的通用性,对于常用电脑,我个人一般会保持以下习惯:
- 尽量使用包管理器来安装工具。
我喜欢用 scoop,可能对于一些人来说输入命令有点麻烦,不过好处也显而易见。可以通过命令的形式进行自动化、半自动化操作。可以方便的进行导入和导出。并且安装应用会自动管理环境变量。 - 利用好 DOpus 的别名以及规划目录
DOpus 文件夹别名Folder Aliases 的文件夹别名模块,对统一管理路径和集成非常的有用,这可以保证,当我们因为迁移、还原备份等原因需要修改脚本路径时,不需要修改脚本中硬编码的路径,而是编辑别名对应的目录即可。别名本身的大小写不敏感的,即MyName和myname是一样的。
对于外部脚本,如果你会使用 Git 之类的版本管理工具,最佳实践可能是在 DOpus 中设置脚本目录的别名,比如 script_py 、script_js,然后在 DOpus 中就可以通过别名来使用,比如执行内置命令 GO /script_py 或 GO {alias|script_py} 都可以跳转到相应目录。
对于一些比较轻量的脚本,也可以放在 DOpus 本身的脚本管理目录 Script AddIns 中,可以通过内置别名 GO /Scripts 访问。把脚本放这个目录下的好处是:与其他脚本文件统一管理,可以利用 DOpus 的备份恢复来同步脚本。并且在 DOpus 内部可以使用内置的别名。
案例 1:通过按钮调用外部脚本
这是一个挺常用的场景。
比如选中某些文件,然后点击一个自定义按钮,将选中的文件作为目标参数传给脚本。
比如我在 Script AddIns/Extra 目录中有一个自定义的外部脚本 trans_text.py,接受两个参数: -i 表示目标文件的绝对路径(多个),-t 表示目标语言。下方的脚本仅作为示例,功能就是在控制台输出接收到的参数,并且在同目录下生成一个日志文件。
# trans_text.py
import argparse
import logging
from pathlib import Path
def main():
# 日志文件放在脚本同目录
script_dir = Path(__file__).parent
log_file = script_dir / "trans_text.log"
# 配置日志
logging.basicConfig(
filename=log_file,
level=logging.INFO,
format="%(asctime)s - %(message)s",
encoding='utf-8'
)
parser = argparse.ArgumentParser(description="输出传入的文件路径与目标语言")
parser.add_argument("-i", "--inputs", nargs="+", required=True, help="文件路径列表")
parser.add_argument("-t", "--target", required=True, help="目标语言")
args = parser.parse_args()
# 输出内容
msg = f"目标语言:{args.target}\n接收到 {len(args.inputs)} 个文件路径:\n" + "\n".join(args.inputs)
# 打印到控制台
print(msg)
# 写入日志
logging.info(msg)
if __name__ == "__main__":
main()
在命令行中调用方式是:
python "脚本目录的绝对路径\trans_text.py" -i "文件A路径" "文件B路径" -t "zh_CN"
我希望实现:在 DOpus 有一个自定义按钮,选中多个文件,然后点击按钮,弹出一个语言选项,选择确认后调用脚本。
首先先新建按钮,函数定义中的类型选择 标准功能(DOpus或外部程序),然后在下方的脚本编辑区域输入命令即可。如果是外部命令,会相当于用默认的终端执行。
所以,如果配置过 python 环境,我们是可以直接使用 python 命令的。
直接调用
python "{alias|script_py|noterm}/trans_text.py" -i {allfilepath$} -t "{dlgchoose|选择语言|default:简体中文=zh-CN+英语=en-US+日语=ja}"
拆解一下这条命令:
"{alias|script_py|noterm}/trans_text.py"表示调用的脚本路径,前面用到了别名,其中|noterm是一个修饰符,表示去除路径最后的路径分隔符。{allfilepath$}是传递文件名代码,表示选中状态的所有文件完整路径,其中末尾的$表示这个参数是必须的,如果为空,则不执行整条命令。"{dlgchoose|选择语言|default:简体中文=zh-CN+英语=en-US+日语=ja}"是对话框代码,允许在命令执行前,根据用户的输入获取参数。这里是弹出一个下拉对话框,内容是有默认值的语言列表。
在执行命令前,可以把下方的运行并记录日志选中,这样控制台就会输出实际执行的命令,方便我们复制命令出来调试。

如果我们不选中任何文件,直接点击运行。那么会发现控制台没有任何输出,因为我们上面使用了 {allfilepath$}。
如果我们选中了文件,点击运行。会发现一闪而过一个黑色窗口,然后脚本目录下多了一个同名日志文件,内容应该是输入参数。这就说明我们调用脚本成功了。
控制状态
因为前面我们使用了 {allfilepath$} 来确保命令只有在选中文件时才会执行。但是其实我们还可以通过命令修饰符来控制按钮的可点击状态,这使得交互体验更加友好。
比如在脚本最上方增加命令 @disablenosel,表示 当未选择任何文件或文件夹时,将被禁用。保存后我们会发现,没有选中文件时,按钮变成灰色不可点击状态了。
@disablenosel
python "{alias|script_py|noterm}/trans_text.py" -i {allfilepath$} -t "{dlgchoose|选择语言|default:简体中文=zh-CN+英语=en-US+日语=ja}"
同理,还有 @hidenosel 表示 当未选择任何文件或文件夹时,将被隐藏。
指定 Shell 和不关闭运行窗口
我们会发现,在点击按钮后,会打开一个终端窗口,然后执行脚本后再关闭。
有时候我们希望不关闭这个窗口,能够更方便我们查看执行结果。或者是希望通过指定的 Shell来运行脚本,比如 cmd 或 PowerShell。
可以用 cmd /k 命令 或 powershell -NoExit -Command "& {命令}" 来实现脚本运行完毕后不关闭窗口。
需要注意的是:如果使用 PowerShell ,因为 -Command 命令是用双引号包裹的,因此内部实际执行命令的双引号是需要转义的。
我们的命令可能会变成以下形式,编写和调试脚本都会变得相当麻烦:
@disablenosel
powershell -NoExit -Command "& {python \"{alias|script_py|noterm}/trans_text.py\" -i \"{allfilepath$}\" -t \"zh_CN\" }"
为了避免转义,我们可以进行以下几个操作来减少转义:
- 利用设置局部变量命令
@set设置一个变量,然后使用{$变量名}来引用 - 需要使用环境变量,可以使用语法
%环境变量名称% - 指定PowerShell 并使用
-Command参数时,命令中用单引号'代替双引号"来包裹路径参数,动态参数通过 DOpus 的外部控制码或局部变量以及环境变量注入。
对于指定CMD 并且不关闭窗口来说,就变得很简单:
@disablenosel
@set user_dir=%USERPROFILE%
@set cmd_str = python "{alias|script_py|noterm}/trans_text.py" -i {allfilepath$} -t "{dlgchoose|选择语言|default:简体中文=zh-CN+英语=en-US+日语=ja}"
@output: user dir is :{$user_dir}
cmd /k {$cmd_str}
对于指定Powershell 并且不关闭窗口来说,需要注意转义问题:
- 方案 1:将命令变量中包裹参数的双引号改成单引号,后面实际调用命令时用双引号包裹
@disablenosel
@set user_dir=%USERPROFILE%
@set cmd_str=python '{alias|script_py|noterm}/trans_text.py' -i '{allfilepath$}' -t '{dlgchoose|选择语言|default:简体中文=zh-CN+英语=en-US+日语=ja}'
@output: user dir is :{$user_dir}
powershell -NoExit -Command "& { {$cmd_str} }"
- 方案 2:利用求值器进行替换
这里利用到求值器语法{=求值器表达式=},并使用Replace函数将变量$cmd_str中的双引号全部替换为单引号。
@disablenosel
@set user_dir=%USERPROFILE%
@set cmd_str=python "{alias|script_py|noterm}/trans_text.py" -i "{allfilepath$}" -t "{dlgchoose|选择语言|default:简体中文=zh-CN+英语=en-US+日语=ja}"
@output: user dir is :{$user_dir}
powershell -NoExit -Command "& { {=Replace($cmd_str,"""","'")=} }"
执行时隐藏窗口
如果不希望执行时终端一闪而过或者出现调用工具的界面,可以在上方增加一个运行模式的命令 @runmode:hide,表示运行时隐藏。