## 开始前先把XYplorer几个缺点先说了
访问任何"网络"下路径十分缓慢
右键菜单可能会崩溃
Windows必备神器-Explorer++(高速文件资源管理器)
哪天65发个贴介绍一下w
本篇未完成,内容可能会变动,请以文章最新版本为准
正文
Xyplorer(官方发音[ɛks-waɪ-plorer],可发音为[zaiplorer],简称XY) 是一个Windows自带资源管理器的替代品:支持多窗格,文件分类、标签,音视频/文件浏览等,有Listary集成和脚本功能,入门门槛十分低。也是65主用的软件w
tags_labels_dark700×250 22.2 KB
软件下载
官网:https://xyplorer.com
镜像:XYplorer 正版软件 - 数码荔枝 x 下载中心
学习版(65建议支持正版!):XYplorer 28.10.0200 Free Download - FileCR
安装后在Help下选择Select language菜单下选择简体中文即可
image944×376 31.2 KB
初步设置
由于XYplorer的设计原则是:不要用功能轰炸用户。 因此用户永远都不知道有这些功能(
与系统和其他软件集成
按F9打开设置菜单:
在系统集成里,勾选以下选项
image850×409 58.7 KB
如果不需要与系统集成,仅将下面两项开启就可以。
若想替代Win+E,打开regedit,找到HKEY_CLASSES_ROOT\Folder\shell\opennewwindow\command项,将(默认)的值改为C:\Program Files (x86)\XYplorer\XYplorer.exe %2(根据XYPlorer安装路径修改),删除DelegateExecute
会在Windows更新以及运行chkdsk时恢复!
在Listary选项里启用与XYplorer的集成,即可使用类似于Ctrl+G之类的listary功能
颜色过滤器
image117×296 11.9 KB
虽然自带一个简易的配置,但是不包含所有的扩展名,这里把65的配置分享,直接粘贴在已有的项或者新的项就可以了
代码/文字
*.htm;*.html;*.php;*.txt;*.css;*.js;*.json;*.xml;*.md;*.csv;*.log;*.ini;*.cfg;*.config;*.sql;*.py;*.java;*.cpp;*.c;*.h;*.cs;*.rb;*.pl;*.sh;*.bat;*.ps1;*.vbs;*.asp;*.aspx;*.jsp;*.cfm;*.inc;*.yaml;*.yml;*.toml;*.rst;*.tex;*.text;*.conf;*.properties;*.srt;*.ass;*.xaml;*.svg;*.info;*.nfo;*.go;*.swift;*.kt;*.ts;*.tsx;*.jsx;*.vue;*.scss;*.sass;*.less;*.styl;*.asm;*.bas;*.f;*.for;*.pas;*.dpr;*.lua;*.m;*.r;*.rs;*.scala;*.clj;*.cljs;*.edn;*.hs;*.lhs;*.erl;*.hrl;*.fs;*.fsx;*.fsi;*.ml;*.mli;*.re;*.res;*.coffee;*.graphql;*.gql;*.proto;*.thrift;*.ebuild;*.bb;*.mak;*.cmake;*.pro;*.pri;*.feature;*.manifest;*.dockerfile;*.gitignore;*.gitattributes;*.editorconfig;*.lock;*.patch;*.diff;*.pem;*.crt;*.key;*.p12;*.pfx;*.cer;*.pub;*.asc;*.gpg;*.env;*.example;*.sample;*.template;*.bak;*.old;*.orig
纯文本
*.txt;*.ini,*.log,*.csv
文档:
*.doc;*.docx;*.docm;*.dot;*.dotx;*.dotm;*.pdf;*.ppt;*.pptx;*.pptm;*.pot;*.potx;*.potm;*.pps;*.ppsx;*.ppsm;*.xls;*.xlsx;*.xlsm;*.xlt;*.xltx;*.xltm;*.xlsb;*.xla;*.xlam;*.xll;*.xlw;*.odt;*.ods;*.odp;*.odg;*.odf;*.rtf;*.wpd;*.pub;*.xps;*.oxps;*.vsd;*.vsdx;*.vsdm;*.vss;*.vssx;*.vssm;*.vst;*.vstx;*.vstm;*.vdw;*.mpp;*.mpt;*.xml;*.html;*.htm;*.mht;*.mhtml;*.epub;*.fb2;*.djvu;*.xmind; *.vsdx;*.svg;
图片
*.png;*.jpg;*.jpeg;*.gif;*.bmp;*.tiff;*.tif;*.webp;*.svg;*.ico;*.psd;*.ai;*.raw;*.cr2;*.nef;*.arw;*.orf;*.rw2;*.dng;*.heic;*.heif;*.avif;*.jxr;*.wdp;*.jp2;*.jpm;*.jpx;*.j2k;*.j2c;*.pbm;*.pgm;*.ppm;*.pnm;*.exr;*.hdr
压缩包
*.zip;*.rar;*.7z;*.tar;*.gz;*.bz2;*.xz;*.tar.gz;*.tgz;*.tar.bz2;*.tbz2;*.tar.xz;*.txz;*.arj;*.lzh;*.lha;*.cab;*.iso;*.img;*.dmg;*.wim;*.swm;*.vhd;*.vhdx;*.qcow2;*.vmdk;*.z;*.taz;*.jar;*.war;*.ear;*.apk;*.ipa;*.xpi;*.deb;*.rpm;*.tar.zst;*.zst
音视频
*.mp3;*.wav;*.aac;*.m4a;*.flac;*.ogg;*.oga;*.wma;*.aiff;*.aif;*.aifc;*.opus;*.amr;*.mp2;*.ac3;*.au;*.snd;*.ra;*.ram;*.rm;*.mid;*.midi;*.m4b;*.m4p;*.m4r;*.3gp;*.3g2;*.caf;*.gsm;*.dts;*.dsd;*.dvf;*.msv;*.mka;*.tta;*.voc;*.vox;*.weba;*.8svx;*.dss;*.act;*.ape;*.mpc;*.spx;*.tak;*.wv
其他设定
image430×142 7.21 KB
65建议打开后台处理,否则在复制文件时会阻塞操作。
image534×147 19.5 KB
删除其中*.txt强制使用系统自带记事本打开的项
开始使用
一开始使用,肯定会发现的是右键菜单里的重命名消失了,XYPlorer中,除键盘上的快捷键外,重命名为鼠标同时按下左键+右键触发(与部分鼠标手势软件冲突,记得设定黑名单)
常见快捷键
以下提到的所有快捷键都可以修改
展示/隐藏地址栏 Ctrl+Shift+F12
自定义键盘快捷键 Shift+F9
创建新文件夹 Ctrl+N
创建新文本文件Ctrl+Shift+N
创建新的路径:Ctrl+Alt+N
新建标签页:Ctrl+T
关闭标签页:Ctrl+W
标签页支持鼠标滚轮滚动w
image570×201 25.5 KB
双窗格模式:F10
切换活动窗格:Ctrl+Alt+F10
交换窗格:Ctrl+Shift+F10
浏览文件内容窗格:Ctrl+F11
收藏文件夹Ctrl+B
鼠标双击菜单空白处或者F7 或 Alt+Backspace 或 Alt+ ← 即可返回上一级目录
Ctrl+Z尝试撤回上一步(删除、重命名等等),最多255步
以及刷新功能的快捷键
image495×278 30.8 KB
搜索/筛选文件
如果只是想在该目录内快速搜索文件,直接按键盘上的按键就可触发,此时会列出所有文件开头为你键入的字母的功能
同时也可在下面搜索(支持正则表达式)该目录的文件和文件夹
对于搜索当前目录和所有子目录,可以用F3展开快速搜索
image779×340 22.5 KB
支持通配符和部分匹配,例如:
readme.txt = 查找所有名为 readme.txt 的文件
black = 查找所有名称中含有“black”的项目
b* = 查找以字母 b* 开头的所有项目
*.PNG = 查找所有 PNG 文件
* = 查找所有项目
* /f = 查找所有文件(没有文件夹)
*.txt /n = 查找所有TXT文件的(不递归子文件夹)
标签也可以被搜索,例如:
lbl:red = 所有标有“red”的项目
cmt:chicago = 查找所有备注中有“chicago”的项目
tags:cats|dogs = 查找所有标签为“cats”或“dogs”的资料
还有布尔(:)和正则表达式(>)模式,例如:
:!# = 查找所有名称中没有数字的项目
:*.jpg | *.png = 查找所有JPG和PNG图像
:*.jpg or *.png = 查找所有的JPG和PNG图像
:tags:cats AND name:a* = 查找所有标签为“cats”并以 a* 开头的项目
.*(.jpg|.png)$ = 查找所有JPG和PNG图像
对于搜索其他路径以及更高级的搜索,快捷键为Ctrl+F
image1931×414 105 KB
对于文件过滤,可以靠Ctrl+J打开快速筛选器,或选择上方 绿色漏斗图标打开设定好的常见选项
image482×901 84.8 KB
在这些选项关闭之前,它们会一直起作用,就算切换目录也会保留w
标签/标注/自定义文件图标
Alt+Shift+F9或在上方可以开启自定义文件图标
image981×361 44.7 KB
右键标题栏,可以选择打开标签和标注
image317×122 4.87 KB
标注可以在设置>标签信息里修改,是固定的,一个文件/文件夹只能同时有1个标注
image448×433 17.2 KB
标签与L站的标签类似,一个文件/文件夹可以同时拥有无数个标签
image458×198 9.13 KB
在对应的栏里右击即可修改标签和标注。
多窗格
(WIP)
标签页
XYplorer特色功能,每个标签页都可以重命名,修改颜色,而且支持鼠标滚轮滑动
编目 (Catalog)
可以快速创建菜单,快捷方式,文件,以及一键操作等。
通过Ctrl+F8开关。
由于需要用户自行编写,这里先不提及w
快速访问
新版中,XYPlorer新添了快速访问选项,默认位于左侧文件栏最上方
image672×232 19.6 KB
可以通过右键 快速访问 来 修改显示的文件夹
脚本
XYplorer支持自己写脚本,格式为.xys(也就是说还要学 ),于2008年随着XYPlorer 7.0发布。
点我跳过这一章节
快速入门
打开菜单 脚本 → 运行脚本...
在编辑框里粘贴 msg "Hello world!"
点击 确定
看到一个写着 “Hello world!” 的消息框了吧?恭喜,你已经写出了第一个 XYplorer 脚本!
好,接下来试试更有趣的:
试试 msg %temp%。你会看到一个显示你系统 TEMP 文件夹路径的消息框。%temp% 是标准的 Windows 环境变量。
试试 msg "XYplorer.exe 在
试试 msg "按下“确定”复制当前时间!"; copytext "
试试 set $a, "
试试 $a = "Year " . "
理解命令的基本写法
看了上面的例子,你可能已经注意到一些规律了:
命令通常由一个 命令名(比如 msg 或 copytext)和一些 参数 组成。参数可以是 字面值(比如 "Hello!")或者 变量(比如 %temp% (环境变量),
一个参数可以由多个部分组成,部分之间用 点号 (.) 连接起来。
一个命令可以有多个参数,参数之间用 逗号 (,) 分隔。
一个脚本可以包含多个命令,命令之间用 分号 (;) 分隔。
参数的位置很重要。要么按顺序写,要么可以用数字加 := 来指定参数的位置(下面会讲)。
举例:
这个脚本会给所有当前选中的文件(夹)重命名,在后面加上当前日期:
rename b, "*-
这个脚本会先跳转到桌面文件夹(并确保列表没有被过滤),然后按修改日期降序排序,选中第一个项目,最后把焦点移到文件列表上:
goto "Desktop|"; sortby m, d; sel 1; focus "L";
参数编号(高级技巧)
有时候命令有很多参数,用逗号分隔写起来容易数错位置。这时,你可以给参数加上编号前缀。格式是 编号:=参数值,第一个参数的编号是 0。
比如,原来你可能这么写(注意那些连续的逗号):
text popupmenu("A,B,C", , , , , , ",");
现在可以这样写,直接指定第 6 个参数(编号从 0 开始,所以是 6):
text popupmenu("A,B,C", 6:=",");
甚至可以打乱顺序写:
text popupmenu(6:=",", 0:="A,B,C");
或者这样(脚本从左到右处理,后面写的会覆盖前面同编号的):
text popupmenu("a,b", 6:=";", 6:="|", 6:=",", 0:="A,B,C"); // 最终分隔符还是逗号
连接字符串和变量
想把几个字符串或者变量拼在一起?用点号 (.) 就行。点号周围有多少空格都没关系。下面这几行脚本效果完全一样:
msg "Hi there!"
msg "Hi "."there!"
msg "Hi " . "there!"
msg "Hi " . "there!"
msg "Hi"." "."there!"
引号的使用
虽然现在 XYplorer 不强制要求字符串要加引号(比如 msg Hi! 也能运行),但是由于在未来可能会更改,所以,建议用引号括起字符串。
关于引号,有几条基本规则:
所有东西要么在双引号里,要么在单引号里,要么在引号外面。
在双引号里面再用双引号写两个双引号 ("")。
在单引号里面再用单引号,写两个单引号 ('')。 (请注意不是反斜杠)
变量在 双引号里 和 引号外 会被替换成它的值,但在 单引号里 不会。
看例子:
// 变量
msg "XYplorer 在
// 变量
msg 'XYplorer 在
// 想显示 "Quoted" 这个词(带引号)
msg """Quoted"""; // 双引号里用两个双引号表示一个双引号
msg "'Quoted'"; // 或者用单引号包起来
// 想显示 'Quoted' 这个词(带引号)
msg "''Quoted''"; // 单引号里用两个单引号表示一个单引号
msg '"Quoted"'; // 或者用双引号包起来
命令 vs 函数
脚本里有两种东西:命令(Commands)和 函数(Functions)。
命令(比如 echo)是执行一个动作。
函数(比如 quote())是执行一个动作,并且会 返回一个值 到它所在的位置。
看个例子,我们想显示带引号的 “Hi!”:
// 方法一:用命令 echo 和双引号嵌套
echo """Hi!"""; // 输出 "Hi!"
// 方法二:用函数 quote() 来加引号,再用 echo 显示
echo quote("Hi!"); // 输出 "Hi!"
关于函数要注意:
函数名不区分大小写:QUOTE() 和 quote() 是一样的。
就算函数不需要参数,括号 () 也 必须写,不然 XYplorer 认不出它是函数(比如 quote())。
如果忽略函数的返回值,也可以调用它(但括号还是要写!):renameitem("John", , , "-01"); // 直接调用,忽略返回值
// 或者用 call 命令明确表示忽略返回值
call renameitem("John", , , "-01");
函数在 双引号里 不会被执行和替换。比如 msg "现在时间是:get('time')" 只会显示 “现在时间是:get(‘time’)”,而不会显示真正的时间。
命令前缀
现在可以在命令前加个前缀来改变它的行为,用 | 分隔。目前只有一个前缀:
e = 跳过详细的错误框
比如,你在驱动器列表里运行这个重命名命令会报错:
rename , '*-
加上 e 前缀就不会弹那个大对话框了:
e|rename , '*-
快速脚本
想快速运行一小段脚本?在脚本前面加上 :: (两个冒号),然后把它粘贴到任何能处理路径的地方,比如地址栏、转到、收藏夹、随身目录等,按回车就能执行!
试试看:
在地址栏粘贴 ::msg "Hello world!",然后按回车。是不是又看到那个熟悉的消息框了?
对于鼠标党,随身目录 (Catalog) 是存放快速脚本的好地方。
按编号运行脚本
在 XYplorer 里,几乎每个菜单项、工具栏按钮对应的功能都有一个固定的编号,叫做 功能 ID。在脚本里,你可以用 # 加上这个 ID 来调用对应的功能。上面例子里的 #1026 正好就是“杂项 / 查找文件 / 打开查找文件并重置”这个功能的 ID。
怎么找到功能的 ID 呢?
打开菜单 工具 → 自定义键盘快捷键...
在对话框里找到你想要的功能(比如在“杂项”分类里找到“打开查找文件并重置”)。
对话框底部会显示这个功能的 ID。旁边有个按钮,点击它就能把 # 加上 ID 复制到剪贴板,方便你在脚本里使用。
比如,#230 会弹出“编辑”菜单下的“新建”子菜单。几乎所有 XYplorer 的内置功能都可以这样通过 ID 在脚本里调用。
单步调试模式
假设你拿到一个脚本,里面写着 #230,若忘记了#230是什么,可以进入 单步模式:
打开 脚本 菜单,勾选 单步模式。
现在再去运行那个脚本。
这时会弹出一个小窗口,叫 单步对话框。它会告诉你脚本 将要 执行哪一步。你可以选择:
继续: 执行当前这一步,然后停在下一步。
跳过: 不执行当前这一步,直接跳到下一步。
取消: 终止整个脚本的执行。
继续执行不进入单步模式: 执行完当前脚本剩下的所有步骤,不再停顿。
在单步模式下,你可以完全掌控脚本的执行,非常安全。强烈建议在编写和调试脚本时开启它!
工具栏上也有一个按钮可以开关单步模式。当单步模式开启时,按钮会变红,非常醒目。
错误信息和风险等级
单步对话框不仅能告诉你脚本错在哪里,还会提示你将要执行的命令有多大风险。风险等级分为:
#3 (黄色警告图标): 有潜在风险,因为功能 ID 可能指向某个危险操作(比如未知的内部命令或用户自定义命令):#[功能 ID]
#2 (黄色警告图标): 有潜在风险,因为会影响文件或文件夹:backupto, copyto, delete, download, moveto, new, open, openwith, rename, rotate, run, setkey, swapnames, timestamp
#1 (黄色警告图标): 有潜在风险,因为它会退出单步模式:unstep
#0 (蓝色弹珠图标): 无害(其他所有命令)
脚本来源和标题
单步对话框的头两行会显示:(1) 当前脚本来自哪里(比如哪个文件),(2) 当前脚本的标题(如果有的话)。这在调试复杂脚本时非常有用。
函数如何单步执行
函数也是可以一步步执行的。当单步停在一个包含函数的行时,如果当前要执行的是函数而不是该行的主命令,那行代码会显示为绿色。你甚至可以单独 跳过 一个函数。如果跳过,函数会返回它的名字和参数,而不是执行结果。
比如这个脚本:
msg quote(chr(64));
如果你一路 继续,结果是消息框显示 @。
如果你跳过 chr() 但继续 quote(),结果是消息框显示 "chr(64)"。
如果你继续 chr() 但跳过 quote(),结果是消息框显示 quote(@)。
如果你两个函数都 跳过,结果是消息框显示 quote(chr(64))。
如果你在单步执行函数时点了 继续执行不进入单步模式,那么只是当前这一行/命令里的所有函数不再单步,下一个命令还是会进入单步模式的。
变量... 按钮
在单步对话框里,点击 变量... 按钮,会弹出一个新窗口列出当前脚本定义的所有变量和它们的值。你可以双击列表里的变量查看它的详细值。
右键点击这个按钮还有更多选项:
显示用户函数: 列出当前定义的所有用户自定义函数。双击可以查看函数的代码。
脚本与用户自定义命令 (UDC)
对于键盘党来说,用户自定义命令 (User-Defined Commands, UDC) 是个好东西。你可以把带 :: 前缀的脚本直接填到一个“转到”类型的 UDC 的“位置”字段里,然后给这个 UDC 分配一个快捷键。
试试看:
点击菜单 用户 → 管理命令...
选择分类 转到,然后点 新建 按钮。
在“位置”字段输入 ::text "
分配一个快捷键,比如 Ctrl+Alt+3。
点击 确定。
现在按下 Ctrl+Alt+3。你会看到一个小窗口,显示当前剪贴板里的文本内容。
另外,有专门的 运行脚本 类型的 UDC,它接受脚本时不需要 :: 前缀,比如直接填 text "
运行脚本 类型的 UDC 还能处理更复杂的东西,比如多行脚本、包含多个脚本的脚本文件等。
多行脚本和多脚本资源
一个脚本可以写成多行(多行脚本),一个脚本文件或资源里可以包含多个脚本(多脚本)。对于多行脚本,有一条重要的格式规则:
在一个多行脚本中,除了第一行之外的所有行,都必须至少缩进一个空格。
任何没有缩进的行都会被认为是新脚本的开始。如果一个脚本资源里包含了多个脚本(即多脚本),那么运行它时会弹出一个菜单,让你选择要运行哪个脚本。
例子: 这是一个包含两个多行脚本的多脚本资源。第一个脚本的标题(会用作菜单项)写在第一行。
// 脚本1:转到 C 盘并选择 calc.exe
"转到 C:\"
goto "C:\";
selectitems "calc.exe";
// 脚本2:转到 Windows 系统目录
"转到系统目录"
goto "%winsysdir%";
运行这个资源时,会弹出菜单:
转到 C:\
转到系统目录
注释是个例外:你可以在多行脚本前面加任意多行不缩进的注释。实际上,不缩进的注释可以插在任何地方。下面这个脚本和上面那个功能完全一样:
// 注释 1
// 注释 2
"转到 C:\"
// 注释 3
goto "C:\";
// 注释 4
selectitems "calc.exe";
// 注释 5
// 注释 6
"转到系统目录"
// 注释 7
goto "%winsysdir%";
// 注释 8
初始化和终止脚本 (_Initialize / _Terminate)
在多脚本资源里,你可以定义两个特殊名字的脚本:_Initialize 和 _Terminate。它们可以放在资源里的任何位置,并且不会显示在弹出的选择菜单里。
_Initialize 脚本会在弹出菜单 之前 自动执行。
_Terminate 脚本会在你从菜单选择并执行完一个脚本 之后(或者你取消了菜单之后)自动执行。
注意: 如果你通过 Load 或 Sub 命令直接调用多脚本资源里的 某个特定 脚本(而不是让它弹菜单),那么 _Initialize 和 _Terminate 不会 被自动执行。
例子: 这个多脚本先定义了一个永久变量,然后提供几个操作这个变量的选项菜单,最后在结束时清理掉这个变量。
"_Initialize"
// 如果变量已存在,这里不会重置它,会保留现有值
perm $p_a;
// 显式初始化为 0
$p_a = 0;
"_Terminate"
// 脚本结束时移除变量
unset $p_a;
"显示变量值"
echo $p_a;
"加一"
$p_a = $p_a + 1;
echo $p_a;
"减一"
$p_a = $p_a - 1;
echo $p_a;
"加载'加一'脚本 (不触发 Init/Term)"
// 这不会调用 _Initialize / _Terminate
Load "*", "加一";
"加载整个脚本 (触发 Init/Term)"
// 这会调用 _Initialize / _Terminate
Load "*", "*";
"子调用'加一'脚本 (不触发 Init/Term)"
// 这也不会调用 _Initialize / _Terminate
Sub "加一";
脚本文件 (.xys)
我们可以把脚本保存在文本文件里,通常以 .xys 作为扩展名(XYplorer Script File)。当你加载这种文件时,如果里面有多个带标题的脚本,就会弹出一个菜单让你选。
创建一个:
用任何文本编辑器新建一个文件。
粘贴以下内容(这是一个包含三个脚本的多脚本):// 测试小脚本
"转到 C:\"
goto "C:\"
"转到系统文件夹"
goto "%winsysdir%"
"转到 XYplorer 文件夹"
goto "
(注意第二行开始的缩进!)
将文件另存为 test.xys,保存在 XYplorer 的 Scripts 文件夹里。( 脚本 → 转到脚本文件夹 )
现在,在 XYplorer 里,点击菜单 脚本 → 加载脚本文件...,然后打开你刚保存的 test.xys。
应该会弹出一个菜单:转到 C:\
转到系统文件夹
转到 XYplorer 文件夹
选择一个,看看是不是跳转到对应的地方了?
一个脚本文件就像一个脚本库。它就是个简单的文本文件,里面可以有一个或多个脚本。你可以直接调用文件里的某个特定脚本,或者加载整个文件(这时通常会出菜单)。脚本文件里的语法和你在其他地方(比如运行脚本对话框)写的脚本语法完全一样。
脚本文件语法规则总结:
以 // 开头的行是注释,会被忽略。
一个脚本可以跨越多行,只需将第一行之后的行缩进(用空格或 Tab)。
一个文件可以包含多个脚本。加载这种文件时,会根据脚本的 标题 (Caption) 生成一个菜单。
给脚本设置标题的方法是:在脚本的第一行(或前面几行注释之后的第一行)写上用引号包起来的标题字符串。
可以在标题里定义 标签 (Label),这样就能直接运行文件里的某个脚本,跳过菜单。
可以使用 sub 命令在脚本文件内部调用同一个文件里的其他脚本。
可以在标题或标签前加下划线 (_) 来隐藏脚本,使其不出现在菜单里。
如何加载脚本文件:
使用菜单 脚本 → 加载脚本文件...
使用“加载脚本文件”类型的用户自定义命令 (UDC)。
在另一个脚本里使用 load 命令:load "你的脚本文件名.xys";
没错,load 命令意味着一个脚本文件可以加载另一个脚本文件,脚本的可能性是不是越来越大了?
拖放文件到脚本文件上
你可以把文件(或文件夹)直接拖放到 .xys 文件上。在被拖放的脚本内部,可以用
这在双面板模式下特别实用:一个面板放你的各种 .xys 脚本文件,另一个面板放你要处理的文件。
简单例子: 创建一个 drop_on_me.xys 文件,内容如下:
// 显示拖放进来的文件路径
text
!: 你也可以拖放到包含多个脚本的 .xys 文件上。这时会先弹出菜单让你选择用哪个脚本处理,然后你选中的那个脚本里的
例子: drop_on_me_2.xys
"用 Text 显示"
text
"用 Echo 显示"
echo
注意:
如果拖放了多个文件,
如果脚本里没有用到
你也可以把文件拖放到 .xys 文件的快捷方式 (.lnk) 上。
你还可以拖放文本(比如网页上选中的文字)到 .xys 文件(或其快捷方式)上,同样用
脚本文件进阶技巧
标签 (Labels)
通过给脚本添加标签,你可以直接运行文件里的某个特定脚本,而不用看菜单。标签跟在标题后面,用 : (空格-冒号-空格)分隔。
例子:
// 用标签指定脚本
"转到 C:\ : croot"
goto "C:\"
"转到系统文件夹 : system"
goto "%winsysdir%"
"转到 XYplorer 文件夹 : xy"
goto "
如果这个文件保存为 test.xys,那么运行命令 load "test.xys", "system"; 就会直接跳转到系统文件夹,不会弹出菜单。
load 命令还可以接受一个用分号分隔的标签列表,这样你就可以控制菜单里显示哪些脚本以及它们的顺序。详见 load 命令的文档。
通配符标签 *: 如果 load 命令指定了多个标签,标签为 * 的脚本也会被包含进来。比如下面第三个脚本会在运行 load "test.xys", "croot;system"; 时也出现在菜单里:
// 包含通配符标签
"转到 C:\ : croot"
goto "C:\"
"转到系统文件夹 : system"
goto "%winsysdir%"
"转到 XYplorer 文件夹 : *" // 这个也会被选中
goto "
隐藏脚本文件里的脚本
隐藏的脚本不会出现在弹出菜单里,但仍然可以通过 sub 命令或者带标签的 load 命令来执行。要隐藏一个脚本,只需在它的标题或标签前加上下划线 _。隐藏的脚本其实不需要标题。
例子: 创建一个 date.xys 文件,内容如下:
// 这是 date.xys 文件内容
"_date" // 隐藏的脚本,只显示日期
msg "
"_time" // 隐藏的脚本,只显示时间
msg "
"显示日期 : date" // 菜单项1
sub "_date"; // 调用隐藏的 _date 脚本
"显示日期和时间 : datetime" // 菜单项2
sub "_date";
sub "_time"; // 调用隐藏的 _time 和 _date 脚本
现在运行 load "date.xys";。弹出的菜单只会显示 “显示日期” 和 “显示日期和时间” 这两项。
接着运行 load "date.xys", "date";。带有 date 标签的脚本会被直接执行。它只有一个命令 sub "_date";。sub 命令用于调用 同一个脚本文件 里的另一个脚本。这里它调用了标签为 _date 的隐藏脚本,执行 msg "
标题里使用变量
多脚本资源的标题里可以使用 XYplorer 的原生变量(比如
例子: 在“运行脚本”对话框里试试这个:
"转到
goto "
"现在是
msg "是的,现在是
如果你等几秒再点击第二个菜单项,你会发现标题里显示的时间和消息框里显示的时间不一样,因为它们是在不同时刻被解析的。
菜单项的图标、状态和层级
你可以给多脚本菜单的每个项定义图标和状态(比如是否选中、是否禁用)。
语法:
"标题|图标|状态|层级 : 标签"
图标 (Icon): 可以是任何文件或文件夹的路径(会用它的小图标),也可以是 PNG, JPG, GIF, BMP, TIF 图片文件的路径。支持 XYplorer 变量和环境变量。如果只写文件名,默认在
也可以用 XYplorer 内部工具栏按钮的关键字,格式是 :关键字 或者 按钮名 / 图标索引,例如 :mru, :hotlist, iexplore / 12。
可以用 *.扩展名 来显示通用文件类型的图标,例如 *.png, *.txt。
可以用 * 作为占位符,让 XYplorer 尝试用标题本身作为路径去找图标。
图标定义里支持永久全局变量。
状态 (State): 是一个数字,表示菜单项的外观。可以组合:
1: 默认(有些系统下可能显示为粗体)
2: 选中状态 (Checked)
4: 禁用状态 (Disabled)
(可以相加,比如 3 = 1+2 = 默认+选中,6 = 2+4 = 选中+禁用)
层级 (Level): 定义菜单的嵌套深度。0 是顶层(默认)。数字越大,嵌套越深。最多支持 256 级。
标签 (Label): 前面讲过,用于直接调用。
状态例子:
"去 C 盘|C:|1" goto "C:\"; // 默认状态 (可能粗体)
"去 D 盘|D:|2" goto "D:\"; // 选中状态
"去 E 盘|E:|3" goto "E:\"; // 默认 + 选中
"去 F 盘|F:|4" goto "F:\"; // 禁用状态
图标例子:
"有趣脚本|Icons\fun.ico" echo "56!"; // 使用
"说 65!|iexplore / 12" echo "65!"; // 使用 IE 图标组的第 12 个图标
"最近位置|:mru" button "mru"; // 使用 'mru' 按钮的图标
"常用列表|:list" button "list";// 使用 'list' 按钮的图标
"图片文件|*.png" echo '图片'; // 使用 PNG 文件类型的通用图标
"C:\|*" goto "C:\"; // 尝试使用 "C:\" 作为图标路径
层级例子(创建子菜单):
"C 盘相关|*" // 父菜单项,层级 0
" 转到 C:\ 根目录|||1" // 子菜单项,层级 1
goto "C:\";
" 转到 System32 并选中计算器|||1" // 另一个子菜单项,层级 1
goto "%winsysdir%";
selectitems "calc.exe";
"D 盘相关|*" // 另一个父菜单项,层级 0
" 转到 D:\ 根目录|||1" // 它的子菜单项,层级 1
goto "D:\";
相对层级: 有时,尤其是在用 include 包含菜单片段时,用相对层级更方便。在层级数字前加 + 号表示相对上一行的绝对层级进行增加。
例如,下面两段代码效果一样:
// 使用绝对层级
"A" echo "A";
"B|||1" echo "B";
"C|||2" echo "C";
"D|||1" echo "D";
"E|||2" echo "E"; // E 是 D 的子菜单
"F|||3" echo "F"; // F 是 E 的子菜单
// 使用相对层级
"A" echo "A";
"B|||+1" echo "B"; // 比 A 深一级 (1)
"C|||+1" echo "C"; // 比 B 深一级 (2)
"D|||1" echo "D"; // 回到层级 1
"E|||+1" echo "E"; // 比 D 深一级 (2)
"F|||+1" echo "F"; // 比 E 深一级 (3)
使用相对层级的好处在于,你可以把一段子菜单结构(比如上面例子里的 B 和 C,或者 E 和 F)定义在一个单独的文件里,然后在主文件里 include 它,它会自动适应当前的嵌套深度。
比如,创建 SubMenu.xys:
// SubMenu.xys
"子项 1|||+1" echo "Sub 1";
"子项 1.1|||+1" echo "Sub 1.1";
然后在主脚本里:
"顶级菜单 A" echo "A";
include "SubMenu.xys"; // 包含的菜单项层级为 1 和 2
"顶级菜单 B|||1" echo "B"; // 设置当前绝对层级为 1
include "SubMenu.xys"; // 包含的菜单项层级为 2 和 3
goto 的简写形式
在多脚本资源(比如 .xys 文件)里,如果你想创建一个简单的跳转菜单项,可以直接写路径,XYplorer 会自动把它转换成带图标的 goto 命令。
完整版本:
"C:\|C:\" goto "C:\";
"C:\Windows|C:\Windows" goto "C:\Windows";
"声音管理器|C:\WINDOWS\SoundMan.exe" goto "C:\WINDOWS\SoundMan.exe";
等效的简化版本:
C:\
C:\Windows
C:\WINDOWS\SoundMan.exe
这种简化还支持环境变量、XYplorer 变量、快速搜索等
更多简化例子:
Desktop // 转到桌面
%tmp% // 转到临时文件夹
C:\WINDOWS\system.ini // 打开文件
C:\WINDOWS\system32 // 转到文件夹
C:\WINDOWS\system32?a* // 转到文件夹并应用快速搜索 a*
C:\WINDOWS\system32?:a* or b* // 转到文件夹并应用视觉过滤器 :a* or b*
C:\WINDOWS\system32?lbl:blue // 转到文件夹并应用标签过滤器 lbl:blue
C:\WINDOWS\system32|a* // 转到文件夹并应用视觉过滤器(旧语法) |a*
注释
脚本里可以写注释,方便自己和他人理解代码。支持两种注释:
行尾注释 (Line End Comments):
从 // 开始(必须在引号之外)一直到该行结束,都是注释。
$a = "
$a = "
assert $a=="
"获取选中数量" // 这是脚本标题,也可以加注释
$count = get("CountSelected"); // 获取选中项数量
assert $count!=0, // 断言数量不为0
"运行脚本前请先选中文件!"; // 断言失败时的消息
块注释 (Block Comments):
从 /* 开始(必须在引号之外)到下一个 */ 结束(必须在引号之外),可以跨越多行。
/* 这里是
一个跨越多行的
块注释
*/ msg "你好!";
msg /* 块注释可以插在任何地方!*/ "你好!" /* 随时随地 */;
关于注释的几点注意:
行尾注释 (//) 和块注释 (/* ... */) 会相互覆盖。谁先出现,谁就决定了后面的内容是注释还是代码。msg "Hi!"; // /* 这不是块注释的开始... 这里是行尾注释
msg /* // 这不是行尾注释的开始... */ "Hi!"; // 这里是块注释
不要嵌套块注释! 很容易犯这个错误,尤其是在想注释掉一大段代码时:/* <-- 开始注释第1层
msg '这是测试'; /* <-- 开始注释第2层,这会出问题! */
...其他代码...
*/ <-- 结束注释第2层,但第1层的注释还没结束,导致语法错误!
如果你想注释掉包含块注释的代码,用行尾注释通常更安全:// /* 这整行都被注释掉了,里面的块注释也没关系 */ msg '测试';
变量 (Variables)
写稍微复杂点的脚本,你很快就会需要用到变量来临时存储数据。XYplorer 允许你定义和使用任意多的变量。
定义和赋值:
最常用的是 = 赋值符:
$a = "你好!"; // 定义变量 $a 并赋值字符串 "你好!"
msg $a; // 显示 $a 的值: 你好!
也可以用 set 命令(效果一样,但 = 更常用):
set $a, "你好!";
msg $a;
变量插值 (Interpolation):
变量定义后,在后面的脚本代码里,如果变量出现在双引号 (") 包裹的字符串里,或者直接出现在引号外面,它会被自动替换成它的值。这叫“插值”。
$name = "65";
msg "你好,我是 $name!"; // 输出:你好,我是 65!
变量的格式和作用域:
变量名必须以美元符号 $ 开头。
$ 后面必须是字母 (a-z, A-Z) 或下划线 (_) 开头。
后面可以跟任意数量的字母、数字 (0-9) 或下划线。
变量名是 区分大小写 的!$a 和 $A 是两个不同的变量。
合法的变量名: $a, $My_Var, $count1, $_temp
非法的变量名: a (没$), $1a (数字开头), my-var (含非法字符-)
默认情况下,变量的作用域和生命周期仅限于当前运行的脚本。脚本运行结束,变量就消失了。
自增/自减运算符 (++ / --)
跟很多编程语言一样,支持 ++(加1)和 --(减1)操作符。
$i = 5;
$i++; // $i 现在是 6
msg $i; // 显示 6
$i = 5;
$i--; // $i 现在是 4
msg $i; // 显示 4
// 如果变量未定义,++ 会让它变成 1
$new_var++;
msg $new_var; // 显示 1
你也可以在命令的参数里直接用 $i++ 或 $i--。注意: 值是 先 被传递给命令/函数,然后 再自增/自减。
$i = 1;
echo $i++; // 先输出 1, 然后 $i 变成 2
echo $i; // 输出 2
$i = 1;
echo 1 + $i++; // 先计算 1 + 1 = 2 并输出, 然后 $i 变成 2
echo $i; // 输出 2
$i = 1;
echo $i++ + 1; // 同上,输出 2, 然后 $i 变成 2
echo $i; // 输出 2
$i = 1;
echo $i++ . $i++ . $i; // 输出 "1", $i变2; 输出 "2", $i变3; 输出 "3" -> 结果 "123"
echo $i; // 输出 3
// 特殊情况:加法运算
$i = 1;
echo $i++ + $i++; // 左边的 $i++ (值1) 先执行, i变2; 然后右边的 $i++ (值2) 执行, i变3; 最后计算 1 + 2 = 3 并输出.
echo $i; // 输出 3
重要历史注意: 在 v14.30.0100 版本之前,$i++/$i-- 是先增/减,再传递值的!现在是先传递,再增/减。
插值的更多细节(如何阻止插值):
用单引号 (') 包裹字符串可以阻止里面的变量被插值替换。
$name = "65";
msg '你好,我是 $name!'; // 输出:你好,我是 $name! (变量没被替换)
// 想显示 %TMP% 这个文本,而不是它的值
msg '%TMP% = ' . %TMP%; // 输出类似: %TMP% = C:\Users\...\AppData\Local\Temp
// 想显示 $date 这个文本,而不是日期
$date = "
msg '$date = ' . $date; // 输出类似: $date = 2023-10-27 15:30:00
变量作用域和生命周期:局部、全局和永久变量
局部变量 (Local Variables)
默认情况下,你在脚本里创建的所有变量都是 局部 的。这意味着:
它们只在定义它们的那个脚本内部有效。
如果一个脚本调用了另一个脚本(比如用 sub 或 load),被调用的脚本有自己的一套全新的局部变量,和调用它的脚本里的变量互不影响。
脚本执行完毕,它的所有局部变量就自动销毁了。
全局变量 (Global Variables)
有时候你确实需要在不同的脚本之间共享变量。这时可以用 全局变量。XYplorer 的全局变量机制类似 PHP,你需要显式地声明一个变量是全局的。
使用 global 命令来声明:
// 在脚本 A 里
global $shared_counter; // 声明 $shared_counter 是全局的
$shared_counter = 0;
load "script_b.xys"; // 调用脚本 B
echo $shared_counter; // 看看脚本 B 有没有修改它
// 在 script_b.xys 里
global $shared_counter; // 在这里也要声明才能访问和修改全局的 $shared_counter
$shared_counter++;
注意: 全局变量虽然方便,但也可能让脚本之间的依赖关系变得复杂,维护起来更困难。请谨慎使用。全局变量的生命周期也只在当前脚本调用链(从最初的脚本到所有被它调用的脚本)结束时终结。
永久变量 (Permanent Variables)
局部和全局变量在脚本(或脚本栈)结束后就消失了。但 永久变量 不一样,它们会一直存在于 XYplorer 的内存中,直到:
手动清除。
XYplorer 进程结束。
(可选配置) 可以在 XYplorer 关闭再打开后仍然保留(在 配置 → 刷新, 图标, 历史 → 记住永久变量 中设置)。
永久变量非常适合在完全不相关的脚本之间,或者跨越很长时间共享数据。
使用 perm 命令来声明:
perm $p_user_preference; // 声明 $p_user_preference 是永久的
// 第一次运行时设置
if ($p_user_preference == "") {
$p_user_preference = input("请输入你的偏好设置:");
}
msg "你上次设置的偏好是: " . $p_user_preference;
在被调用脚本中创建或修改的永久变量,在调用脚本返回后 立即可见/更新。
有两个相关的命令 writepv 和 readpv,可以把永久变量保存到文件,或者从文件加载,非常适合用作轻量级的数据存储。
你可以在 XYplorer 的任何地方(比如地址栏、自定义列)通过
想查看和手动管理当前的永久变量?用菜单 脚本 → 永久变量。你可以在那里 unset (删除) 它们。
想一次性清除所有永久变量?用 releaseglobals 命令。
变量的初始值
局部变量: 如果你使用一个从未被赋值,也未被声明为 global 或 perm 的 $变量名,它会被当作一个普通的字符串,其值就是它的名字本身(比如 "$a")。msg $never_set; // 输出 "$never_set"
全局/永久变量: 当你用 global 或 perm 声明一个变量时,如果它之前从未被赋值过,它会被 初始化为空字符串 ""。global $g_var;
msg $g_var; // 输出 "" (空字符串)
perm $p_var;
msg $p_var; // 输出 "" (空字符串)
数组 (Arrays)
XYplorer 脚本支持两种类型的数组:索引数组 (indexed arrays) 和 关联数组 (associative arrays),语法和 C++/PHP/Java 有点像。
索引数组 (用数字 0, 1, 2… 作为索引)
$a[0] = "6"; // 给索引为 0 的元素赋值
echo $a[0]; // 输出: 6
$a[0] = "6";
$a[1] = "5";
echo $a[0] . $a[1]; // 输出: 65
$a[2] = "12345";
$b = 1;
echo $a[$b + $b]; // $b+$b 等于 2, 输出 $a[2]: 12345
数组元素在引号(双引号)里也能用:
$a[0] = "65";
echo "这是一只 $a[0]!"; // 输出: 这是一只 65!
$a[0] = "0";
$a[1] = "65";
echo "$a[0]$a[1]"; // 输出: 065
关联数组 (用字符串作为键/索引)
键(key)可以用单引号或双引号包起来。
$ci['wi'] = "65"; // 用字符串 'wi' 作为键
echo $pet['wi']; // 输出: 65
echo $pet["wi"]; // 双引号也可以
无效索引或键
如果使用的索引/键不存在,或者格式不对,整个 $var[...] 会被当作普通文本:
$a[0] = "65";
echo "这是一只 $a[1]!"; // $a[1] 不存在,输出: 这是一只 $a[1]!
$b["wi"] = "6565";
echo "这是 $b['wf']!"; // $pet['wf'] 不存在,输出: 这是 $b['wf']!
// 索引/键不能为空
$a[0] = "65";
echo "这是一只 $a[]!"; // 输出: 这是一只 $a[]!
自动创建元素
如果你给一个索引数组中不存在的、非第一个 (索引 > 0) 的元素赋值,那么从 [0] 到那个索引之间的所有元素都会被自动创建,并且值为空字符串 ""。
$new_array[1] = "65"; // 给索引 1 赋值
echo $new_array[0]; // 输出 "" (空字符串, $new_array[0] 被自动创建了)
// 如果只赋值给 [0],则不会自动创建后面的
$another_array[0] = "56";
echo $another_array[1]; // 输出 $another_array[1] (因为它不存在)
复杂的索引/键
索引或键可以是一个表达式:
$n = 4;
$nums[$n + 4] = $n * 4; // 索引是 8, 值是 16
echo $nums[$n + 4]; // 输出: 16
$parts[0] = "user";
$parts[1] = "name";
$data[$parts[0] . $parts[1]] = "65"; // 键是 "username"
echo $data[$parts[0] . $parts[1]]; // 输出: 65
复制数组
你可以把一个数组完整地复制给另一个变量。写不写 [] 都可以。
// 假设 $a 是一个数组
$b = $a; // $b 现在也是 $a 的一个完整副本(独立的)
$c[] = $a[]; // 效果同上
数组的其他特性
数组支持 global 命令,例如 global $my_array[];
数组 不支持 perm 命令(会被忽略)。数组不能是永久性的。
索引数组的索引范围:0 到 32767。
关联数组的最大元素数量:32768。
有几个函数可以帮助处理数组:count() (获取元素个数), explode() (字符串转数组), implode() (数组转字符串)。
特殊函数 array()
有个专门用来创建和填充数组的函数 array()。
如果数组变量不存在,array() 会创建它。
如果数组已存在,array() 会覆盖它原来的内容。
创建索引数组:
$a = array("1", "2", "3");
echo $a[1]; // 输出: 2
// 覆盖原来的数组
$a = array("4");
echo $a[0]; // 输出: 4
echo $a[1]; // 输出 $a[1] (不存在了)
注意:
通常我们直接在 array() 里写字符串值,用逗号分隔。
也可以传递一个包含用逗号分隔的值的变量给 array():$values = "65, 12345";
$arr = array($values); // 注意这里 $values 变量只有一个,所以 $arr[0] 是 "65,12345" 整个字符串
echo $arr[0]; // 输出: 65,12345
// 如果想让 $values 里的逗号起作用,需要先 explode
$values = "65,12345";
$arr = array(explode($values, ", ")); // explode 返回一个数组,array() 再处理
echo $arr[0]; // 输出: 65
值可以用双引号包起来(引号会被移除),如果值本身不含逗号或首尾空格,也可以不加引号:$a = array(6,5); echo $a[0]; // 输出: 6
值也可以用单引号包起来,但单引号不会被移除。
可以在变量名后加 [],效果一样:$a[] = array("猫", "狗");
值按列出的顺序添加到数组,索引从 [0] 开始。
创建关联数组:
$info = array("name" => "neo", "id" => "neo", "forum" => "Linux_do");
echo $info["id"]; // 输出: neo
一般语法:array("键1" => "值1", "键2" => "值2", ...)
同样,如果键和值不含特殊字符,可以省略引号和空格:$info = array(name=>65, stat=>0); echo $info["name"]; // 输出: 65
清空数组:
用 array() 不带任何参数可以清空一个数组(让它变成一个空数组)。
$a = array("w", "i");
echo count($a); // 输出: 2
$a = array();
echo count($a); // 输出: 0
echo $a[0]; // 输出 $a[0] (不存在了)
Foreach 循环遍历数组
要遍历数组中的每个元素,可以用 foreach 循环。数组的 foreach 语法和后面要讲的列表 foreach 有点不同。
基本形式 (只取值):
foreach($数组变量 as $值变量, [标志]) {
// 使用 $值变量 处理每个元素的值
}
$数组变量: 你要遍历的数组。
$值变量: 你起的名字,每次循环,数组中的一个元素的值会赋给它。
标志 (可选):
"r": 反向遍历 (Reverse)。
"e": 跳过空值元素 (Empty skip)。
"re" 或 "er": 两者都用。
例子 (索引数组):
$fruits = array("苹果", "香蕉", "橙子");
foreach($fruits as $fruit) {
echo "我喜欢吃 " . $fruit;
}
// 输出:
// 我喜欢吃 苹果
// 我喜欢吃 香蕉
// 我喜欢吃 橙子
// 反向并跳过空值
$items = array("A", "", "C");
foreach($items as $item, "re") {
echo $item;
}
// 输出:
// C
// A
另一种形式 (同时取键和值):
foreach($数组变量 as $键变量 => $值变量, [标志]) {
// 使用 $键变量 和 $值变量 处理每个元素的键和值
}
$键变量: 你起的名字,每次循环,当前元素的键(索引或关联键)会赋给它。
例子 (关联数组):
// 创建关联数组
$freelancer = array(
"name" => "65",
"email" => "6512345@linux.do",
"id" => 6512345,
);
// 遍历键和值
foreach($freelancer as $key => $value) {
echo "$key: $value";
}
// 输出:
// name: 65
// email: 6512345@linux.do
// id: 6512345
用“键=>值”形式遍历索引数组:
如果你用 foreach($array as $key => $value) 遍历一个索引数组,$key 变量会得到数字索引 (0, 1, 2…)。
$key = "65"; // 循环会覆盖这个变量
$colors = array("红", "绿", "蓝");
$result = array(); // 用一个新数组收集结果
foreach($colors as $key => $value) { // $key 会依次变成 0, 1, 2
$result[$key] = "$key = $value";
}
text implode($result, "|"); // implode 用 | 连接数组元素
// 输出: 0=红|1=绿|2=蓝
嵌套表达式
你可以用圆括号 () 来嵌套表达式,控制运算顺序或者只是为了让代码更清晰。嵌套深度没有实际限制,多余的括号会被自动忽略。
括号只是装饰的例子:
msg "a" . "b"; // "ab"
msg ("a" . "b"); // "ab"
msg ("a") . ("b"); // "ab"
msg (("a") . ("b")); // "ab"
msg ((("a") . ("b"))); // "ab"
msg "a" . "b" . (); // "ab" (空括号没影响)
msg "a" . ("b" . "c"); // "abc"
msg ("a" . "b") . "c"; // "abc"
msg "a" == "a" . "a" == "b"; // 先算 "a"=="a" (1), 再算 "a"=="b" (0), 最后算 1 . 0 -> "10"
msg ("a" == "a") . ("a" == "b"); // 同上,结果 "10"
括号改变运算顺序的例子:
msg "a" == "a" . "a"; // "." 比 "==" 优先级高,先算 "a"."a" -> "aa", 再算 "a"=="aa" -> "0"
msg ("a" == "a") . "a"; // 先算括号里的 "a"=="a" -> "1", 再算 "1"."a" -> "1a"
msg "a" == ("a" . "a"); // 先算括号里的 "a"."a" -> "aa", 再算 "a"=="aa" -> "0"
括号不匹配的错误例子:
msg ("a" . "b"; // 少了右括号 ')'
msg "a" . "b"); // 多了右括号 ')' (或少了左括号)
数学计算
脚本可以进行基本的数学运算,支持的操作符有:
+ 加
- 减
* 乘
/ 除 (结果可能是小数)
\ 整除 (结果是整数,舍弃小数部分)
% 取模 (求余数)
^ 乘方 (指数)
还支持小数、圆括号 () 和一元操作符 +/- (比如 -5, +3)。
例子:
echo 1 + 1; // 2
echo 1 - 2 - 3; // -4 (从左到右计算)
echo 1 - (2 - 3); // 1 - (-1) = 2 (括号优先)
echo 1/3 + 1/3; // 0.666...
echo 1 + 2 * 3; // 7 (乘法优先)
echo (1 + 2) * 3; // 9 (括号优先)
echo 1 / 0; // 错误:除以零!会中断脚本
$a = 3; $b = 2;
echo $a / $b; // 1.5
$fraction = 1.5;
echo $fraction == 3/2; // 1 (True)
echo 1.2 + 2.1; // 3.3
echo 1 + --1; // 1 + (-(-1)) = 1 + 1 = 2
echo --(1 * ----2); // --(1 * 2) = --(2) = -(-2) = 2
echo 5 \ 2; // 2 (整除,舍弃 .5)
echo 5 / 2; // 2.5 (普通除法)
echo 5 % 2; // 1 (5 除以 2 的余数)
echo 2 ^ 3; // 8 (2 的 3 次方)
echo 4 ^ 0.5; // 2 (4 的 0.5 次方,即开平方)
echo 4 ^ -1; // 0.25 (4 的 -1 次方,即 1/4)
几点说明:
字符串转数字: 如果操作数是字符串,XYplorer 会尝试将其转换为数字进行计算。转换规则是从字符串开头取数字,直到遇到非数字字符。
$a = ""; $b = "2"; echo $a + $b; // 0 + 2 = 2
$a = "1a"; $b = "2b"; echo $a + $b; // 1 + 2 = 3
小数点: 为了脚本能在不同地区的电脑上通用,数学计算中的小数点始终是点号 (.),不是根据系统设置变化的(比如德国用逗号,)。
精度: 计算使用标准的 8 字节浮点数。精度足够日常使用,但别指望它像科学计算器那样精确到小数点后十几位。文件管理器能支持脚本就不错了,要那么精确干什么?
运算优先级:
最高: ^ (乘方)
其次: *, / (乘,除)
再次: \, % (整除,取模)
最低: +, - (加,减)
同一优先级的运算符从左到右计算。echo 36 / 4 * 3; // (36/4)*3 = 9*3 = 27 (不是 36 / 12 = 3)
整除和取模的舍入: 在进行整除 (\) 和取模 (%) 运算之前,操作数会先进行四舍五入!
echo 5.9 \ 2.1; // 6 \ 2 = 3 (不是 5 \ 2 = 2)
echo 7.9 % 2.5; // 8 % 3 = 2 (不是 7 % 2 = 1 或其他)
echo 7.9 \ 0.4; // 8 \ 0 -> 错误:除以零
echo 7.9 % 0.4; // 8 % 0 -> 错误:除以零
输入带小数的数字: 写脚本时,用点号 . 作为小数点。如果你非要用系统的区域设置的小数点(比如逗号),必须用引号把它包起来。
echo 7.5 / 2.5; // 3 (推荐,通用)
echo "7,5" / "2,5"; // 3 (只在小数点是逗号的系统上有效)
// 内部存储和显示时,会按系统设置来
$n = 2.5; echo $n; // 如果系统小数点是逗号,会显示 "2,5"
十六进制数 (Hex Numbers)
脚本能识别以 0x (零后面跟小写x) 开头的十六进制数。最多支持 8 位十六进制数字(即 4 字节整数)。会自动转换成十进制值。字母不区分大小写(但前缀 0x 必须是小写 x)。
例子:
echo 0xa; // 10
echo 0xA; // 10
echo 0xFFFFFF; // 16777215
echo 0xFFFFFFFF; // -1 (按有符号 32 位整数处理)
echo 0x7FFFFFFF; // 2147483647 (32 位有符号整数最大值)
echo 0x80000000; // -2147483648 (32 位有符号整数最小值)
echo 0xA + 0xA; // 10 + 10 = 20
无效的十六进制字符串(会原样输出):
echo 0xG; // 0xG (G 不是十六进制数字)
echo 0x; // 0x (没有值)
echo 0XA; // 0XA (前缀必须是小写 x)
echo 0x123456789; // 0x123456789 (太长了,超过 8 位)
echo "0x12345678"; // "0x12345678" (在引号里,不解析)
转换 HTML 颜色值 #RRGGBB 到 XYplorer 能用的十进制颜色值,可以用 0xBBGGRR 的格式
二进制数 (Binary Numbers)
脚本也能识别以 0b (零后面跟小写b) 开头的二进制数。最多支持 32 位二进制数字(即 4 字节整数)。字母 b 必须小写。
例子:
echo 0b0; // 0
echo 0b1; // 1
echo 0b11; // 3
echo 0b10000000; // 128
echo 0b11111111; // 255
echo 0b100000000; // 256
echo 0b00000000000000000000000000000001; // 1
echo 0b10000000000000000000000000000000; // -2147483648 (32 位有符号整数最小值)
echo 0b11111111111111111111111111111111; // -1 (按有符号 32 位整数处理)
无效的二进制字符串(会原样输出):
echo 0b2; // 0b2 (2 不是二进制数字)
echo 0b; // 0b (没有值)
echo 0B1; // 0B1 (前缀必须是小写 b)
echo 0b1100...000; // (超过 32 位) -> 原样输出
echo "0b1"; // "0b1" (在引号里,不解析)
比较运算
你可以比较两个值。比较表达式会原地被替换成结果:1 代表 真 (True),0 代表 假 (False)。
基本形式:
值A 操作符 值B
操作符:
== 等于
!= 不等于
< 小于
> 大于
<= 小于或等于
>= 大于或等于
Like 匹配模式 (区分大小写)
LikeI 匹配模式 (不区分大小写)
UnLike 不匹配模式 (区分大小写)
UnLikeI 不匹配模式 (不区分大小写)
例子:
msg "a" == "a"; // 显示 1
msg ("a" == "a") . ("a" == "b"); // 显示 10 (True 连接 False)
// 用比较结果控制流程 (后面会讲 if 和 ?: )
$result = ("a" == "a"); // $result 是 1
$message = ($result ? "相等" : "不相等"); // $message 是 "相等"
msg $message;
// 检查 XYplorer 版本
$min_ver = "10.0.0";
assert "
// 如果版本低于 10.0.0,会弹出错误消息并停止脚本
字符串和数字的比较:
如果比较的两个值都能被识别为纯数字,那么它们会按数值大小比较。
否则,按字符串比较(字典顺序)。
msg ("2" < "10"); // 1 (True),因为 "2" 和 "10" 都是数字,按数值比
msg ("2" < "10a"); // 0 (False),因为 "10a" 不是纯数字,按字符串比,"2" 在 "1" 之后
msg ("2a" < "10a");// 0 (False),都不是纯数字,按字符串比
Like / LikeI / UnLike / UnLikeI 操作符
用于检查一个字符串是否匹配一个模式(可以使用通配符)。
形式:
字符串 Like 模式 (区分大小写)
字符串 LikeI 模式 (不区分大小写, I = Insensitive)
字符串 UnLike 模式 (不匹配则为 True, 区分大小写)
字符串 UnLikeI 模式 (不匹配则为 True, 不区分大小写)
字符串 是你要检查的文本。
模式 可以包含 XYplorer 常用的通配符:* (任意多个字符), ? (单个字符), # (单个数字), [] (字符集)。
注意: 操作符本身 (Like, LikeI…) 必须精确匹配,且前后要有空格!like 或 LIKEI 都不行。
例子:
echo "abc" Like "a*"; // 1 (True)
echo "Abc" Like "a*"; // 0 (False), 因为大小写不匹配
echo "Abc" LikeI "a*"; // 1 (True), 因为 LikeI 忽略大小写
echo "abc" UnLike "a*"; // 0 (False)
echo "Abc" UnLike "a*"; // 1 (True)
echo "Abc" UnLikeI "a*";// 0 (False)
echo "Abc" LikeI "abC"; // 1 (True), 即使没有通配符,也进行不区分大小写的比较
// 判断是否是 21 世纪
$year = "
$is_21st = ($year Like "20??"); // 检查年份是否是 "20" 开头跟两位任意字符
echo "现在" . ($is_21st ? "是" : "不是") . " 21 世纪";
布尔运算符
用于组合多个比较结果或逻辑值。按优先级从高到低排列:
! 或 not (非 / NOT,一元操作符)
&& (与 / AND)
|| (或 / OR)
and (与 / AND,不区分大小写)
xor (异或 / XOR,不区分大小写)
or (或 / OR,不区分大小写)
例子:
echo ! 1; // 0 (not True -> False)
echo not 0; // 1 (not False -> True)
echo !1; // 0 (可以不用空格)
echo !!!1; // 0 (not not not True -> False)
echo !(1 and 0); // !(False) -> 1 (True)
// 优先级:and 比 or 高
// 解析为:(TRUE and FALSE) or (TRUE and TRUE) -> FALSE or TRUE -> 1 (TRUE)
echo TRUE and FALSE or TRUE and TRUE;
// 在 while 循环中使用
$i = 1;
while ($i < 10 && $i != 5) { // 当 i 小于 10 并且 i 不等于 5 时循环
echo $i;
$i++;
}
echo " 完成"; // 输出: 1234 完成
布尔常量
有两个特殊的常量代表逻辑真假:
TRUE (或 true, True…) 解析为 1
FALSE (或 false, False…) 解析为 0
它们必须不加引号使用才有效。
例子:
echo TRUE and TRUE; // 1 and 1 -> 1
echo TRUE and FALSE; // 1 and 0 -> 0
echo TRUE and false; // 1 and 0 -> 0 (不区分大小写)
echo TRUE and "false"; // 1 and "false" -> 1! 因为 "false" 是字符串,在布尔上下文里非空非"0"即为 TRUE
echo (1 == 1) == TRUE; // (1) == 1 -> 1 (True)
echo (0 == 1) == FALSE;// (0) == 0 -> 1 (True)
echo (1 == 1) != FALSE;// (1) != 0 -> 1 (True)
重要: 在需要布尔值(真/假)的地方(比如 if, while, and, or 的操作数),以下值被视为 FALSE (0):
空字符串 ""
字符串 "0"
数字 0
所有其他值 都被视为 TRUE (1)。
echo "dog" and TRUE; // "dog" -> TRUE, TRUE and TRUE -> 1
echo "dog" == TRUE; // "dog" == 1 -> 0 (字符串 "dog" 不等于数字 1)
echo "0" == FALSE; // "0" == 0 -> 1 (字符串 "0" 等于数字 0)
echo "" == FALSE; // "" == 0 -> 0 (空字符串不等于数字 0)
echo "" XOR TRUE; // FALSE XOR TRUE -> 1
echo "0" XOR TRUE; // FALSE XOR TRUE -> 1
echo "dog" XOR TRUE; // TRUE XOR TRUE -> 0
三元条件运算符 (Ternary Conditionals)
这是一种简洁的 if...else... 写法,常用来根据条件给变量赋不同的值。
逻辑:
如果 (条件为真) {
变量 = 真值;
} 否则 {
变量 = 假值;
}
三元运算符写法:
变量 = (条件) ? 真值 : 假值;
条件: 一个比较表达式或任何可以判断真假的值。
?: 分隔条件和真值。
:: 分隔真值和假值。
真值: 条件为 TRUE 时使用的值。
假值: 条件为 FALSE 时使用的值。
括号 () 和空格是可选的,以下写法等效:
variable = (condition) ? value_if_true : value_if_false;
variable = (condition)? value_if_true: value_if_false;
variable = condition?value_if_true:value_if_false;
例子:
// 根据时间问候
$hour = "
$greeting = ($hour >= "12") ? "下午好" : "上午好";
msg $greeting . "!";
// 判断今天是不是圣诞节
$is_xmas = ("
msg "今天" . ($is_xmas ? "" : "不") . "是圣诞节!";
// 可以直接用在参数里
msg "现在是" . ("
复合赋值运算符
这些是简化运算和赋值的快捷方式。
.= : 字符串连接赋值 ($a = $a . $b 等价于 $a .= $b)
+= : 加法赋值 ($a = $a + $b 等价于 $a += $b)
-= : 减法赋值 ($a = $a - $b 等价于 $a -= $b)
*= : 乘法赋值 ($a = $a * $b 等价于 $a *= $b)
/= : 除法赋值 ($a = $a / $b 等价于 $a /= $b)
\= : 整除赋值 ($a = $a \ $b 等价于 $a \= $b)
例子:
$text = "你好";
$text .= ",世界!"; // $text 现在是 "你好,世界!"
echo $text;
$count = 5;
$count += 3; // $count 现在是 8
echo $count;
$price = 10;
$price *= 0.8; // $price 现在是 8 (打八折)
echo $price;
$value = 11;
$value \= 3; // $value 现在是 3 (11 整除 3)
echo $value;
控制结构
控制结构让你能够改变脚本代码的执行流程,实现条件判断和循环。XYplorer 脚本支持以下几种:
If / ElseIf / Else 块:根据条件执行不同的代码块。
While 循环:只要条件为真就一直重复执行代码块。
For 循环:一种更结构化的循环,通常用于计数。
Foreach 循环:专门用于遍历列表或数组中的每个元素。
Switch 语句:基于一个变量的多个可能值执行不同的代码块。
代码块通常用花括号 {} 包起来。
If / ElseIf / Else 块
通用语法:
if (条件1) {
// 条件1 为 TRUE 时执行的代码
}
elseif (条件2) {
// 条件1 为 FALSE,但条件2 为 TRUE 时执行的代码
}
elseif (条件3) {
// ... 可以有更多 elseif
}
else {
// 以上所有条件都为 FALSE 时执行的代码
}
说明:
if 块是必须的。
圆括号 () 里的条件表达式是必须的。
花括号 {} 包裹的代码块是必须的(即使只有一行代码)。
elseif 块是可选的,可以有零个或多个。
else 块是可选的,最多只能有一个,且必须放在最后。
代码会从上往下检查条件,一旦找到一个为 TRUE 的条件,就执行对应的 {} 里的代码,然后 跳过 后面所有的 elseif 和 else。如果所有 if 和 elseif 的条件都为 FALSE,则执行 else 块里的代码(如果 else 存在的话)。
例子:
// 简单的 if
if (1 == 1) {
echo "数学没问题!";
}
// if...else
$user_input = input("请输入 'yes' 或 'no':");
if ($user_input == "yes") {
echo "你选择了 'yes'";
} else {
echo "你没有选择 'yes' (可能是 'no' 或其他)";
}
// if...elseif...else
$score = 75;
if ($score >= 90) {
echo "优秀";
} elseif ($score >= 60) {
echo "及格";
} else {
echo "不及格";
}
While 循环
通用语法:
while (条件) {
// 只要条件为 TRUE,就重复执行这里的代码
}
说明:
每次循环开始前,都会检查圆括号 () 里的条件。
如果条件为 TRUE,就执行花括号 {} 里的代码块,然后回到开头再次检查条件。
如果条件为 FALSE,就跳过 {} 里的代码块,循环结束,继续执行 while 后面的代码。
如果一开始条件就为 FALSE,那么 {} 里的代码一次也不会执行。
圆括号 () 和花括号 {} 都是必须的。
务必确保循环内部有代码能最终让条件变为 FALSE,否则会变成死循环,可以用 break; 命令强制跳出循环)。
例子:
// 从 1 数到 3
$i = 1;
while ($i <= 3) {
echo $i;
$i++; // 关键!让 $i 变化,否则死循环
}
echo " 完成"; // 输出: 123 完成
// 嵌套 while 循环
$row = 1;
while ($row <= 2) {
$col = 1;
while ($col <= 3) {
echo "行 $row, 列 $col";
$col++;
}
$row++;
}
// 条件一开始就为 false
while (1 == 2) {
echo "这里永远不会被执行";
}
For 循环
通用语法:
for (初始化表达式; 循环条件; 迭代表达式) {
// 循环体代码
}
说明:
初始化表达式 (expression1): 在循环开始前只执行一次。通常用来设置计数器。
循环条件 (expression2): 在每次循环迭代开始前进行判断。如果为 TRUE,执行循环体;如果为 FALSE,循环结束。
迭代表达式 (expression3): 在每次循环迭代结束时执行。通常用来更新计数器。
三个表达式都可以省略,但分号 ; 不能省略。for (;;) 是一个死循环(除非内部有 break)。
圆括号 () 和花括号 {} 都是必须的。
内部处理:
你可以把 for 循环看作 while 循环的一种简写形式。实际上,XYplorer 内部就是这么处理的。
例如,这个 for 循环:
for ($i = 1; $i <= 3; $i++) {
echo $i;
}
…在内部会被转换成等效的 while 循环:
$i = 1; // 初始化表达式
while ($i <= 3) { // 循环条件
// 循环体
echo $i;
// 迭代表达式放在循环体最后
$i++;
}
如果你用单步模式调试 for 循环,就能看到这个转换过程。
Foreach 循环遍历列表 (List)
这种 foreach 用于处理由特定分隔符隔开的字符串列表,比如 item1|item2|item3 或者 a,b,c。
通用语法:
foreach($变量名, 列表字符串, [分隔符="|"], [标志], [空列表提示信息]) {
// 对列表中的每个元素执行这里的代码
}
参数说明:
$变量名: 你指定一个变量名。在每次循环中,列表里的下一个元素(一个子字符串)会被赋给这个变量。循环结束后,该变量保留的是最后一个元素的值。
列表字符串: 包含多个元素的字符串,元素之间由分隔符隔开。
分隔符 (可选): 用来分隔元素的字符(或字符串)。默认是竖线 |。如果想用逗号分隔,就写 ","。如果传入空字符串 "",则会将列表字符串按单个字符分割!
标志 (可选):
"r": 反向遍历列表 (Reverse)。
"e": 跳过列表中的空元素 (Empty skip)。比如 a||c 用 "e" 标志会跳过中间的空元素。
"re" 或 "er": 两者都用。
空列表提示信息 (可选): 如果 列表字符串 为空,并且你提供了这个参数(即使是空字符串 ""),循环体将不会执行,并且会弹出一个显示该提示信息的消息框。如果不提供此参数,空列表不会执行循环体,也不会报错。
例子:
// 用逗号分隔的列表
$list = "苹果,香蕉,橙子";
foreach($fruit, $list, ",") {
echo "水果: " . $fruit;
}
// 反向遍历,用 | 分隔 (默认)
$items = "A|B|C";
foreach($item, $items, , "r") { // 第三个参数(分隔符)为空,使用默认 "|"
echo $item; // 输出 C B A
}
// 跳过空元素
$data = "one||three|four|";
foreach($val, $data, "|", "e") {
echo $val; // 输出 one three four (跳过了空元素)
}
// 嵌套 foreach
foreach($letter, "a|b") {
foreach($number, "1,2", ",") {
echo $letter . $number; // 输出 a1 a2 b1 b2
}
}
// 处理选中的文件列表 (
foreach($filepath,
echo "选中的文件: " . $filepath;
}
// 处理选中文件,如果没选中则提示
$selected =
foreach($item, $selected, "|", , "请先选中文件!") {
// 只有选中了文件才会执行到这里
echo "处理: " . $item;
}
// 按字符分割字符串
$word = "你好";
foreach($char, $word, "") { // 分隔符为空字符串
echo "字符: " . $char; // 输出 字符: 你 字符: 好
}
Switch 语句
当你需要根据同一个变量(或表达式)的不同值来执行不同的代码时,switch 语句通常比写一长串 if...elseif...else 更清晰、有时也更高效。
通用语法:
switch (表达式) {
case 值1:
// 当表达式的结果等于 值1 时执行的代码
break; // 跳出 switch 语句
case 值2:
// 当表达式的结果等于 值2 时执行的代码
break;
case 值3:
// ... 可以有很多 case
break;
default:
// 当表达式的结果不匹配上面任何一个 case 时执行的代码
// default 是可选的
}
说明:
switch 后面的圆括号 () 里的表达式只会被计算一次。
然后,计算结果会从上到下依次与每个 case 后面的值进行比较。
一旦找到匹配的 case,就会执行该 case 下面的代码,直到遇到 break; 语句。
break; 语句的作用是跳出整个 switch 结构,继续执行 switch 后面的代码。
非常重要: 如果省略了 break;,代码会继续执行下去,进入下一个 case 的代码块(无论下一个 case 的值是否匹配),直到遇到 break; 或者 switch 结束。这有时是故意为之(称为 “fall-through”),但多数情况是忘了写 break; 导致的 bug。
case 后面的值可以是字面量(字符串、数字)或变量/表达式。比较时使用 == 的规则。
case 后面可以用冒号 : 也可以用分号 ;。
default: 是可选的。如果提供了,它会在所有 case 都不匹配时执行。default 后面也可以跟 break;,虽然通常没必要(因为它已经是最后一个了)。
例子:
// 基本用法
$fav_color = "蓝色";
switch ($fav_color) {
case "红色":
echo "你喜欢红色!";
break;
case "蓝色":
echo "你喜欢蓝色!";
break;
case "绿色":
echo "你喜欢绿色!";
break;
default:
echo "你喜欢的颜色不是红、蓝、绿中的一种,是:" . $fav_color;
// default 后面通常不需要 break
}
echo " Switch 结束";
// case 值可以是表达式
$a = 3; $b = 7; $c = 10.5; $d = 2;
switch ($a * $b) { // 计算 $a * $b = 21
case $c * $d: // 计算 $c * $d = 21
echo "结果等于 $c * $d = " . ($c * $d);
break; // 匹配!执行这里然后跳出
default:
echo "结果是其他值。";
}
// 故意省略 break 实现 "fall-through"
$grade = "B";
switch ($grade) {
case "A":
echo "表现优异!";
// 没有 break, 会继续往下执行
case "B":
echo "表现良好。";
// 没有 break
case "C":
echo "需要努力!";
break; // 在这里跳出
case "D":
echo "不及格。";
break;
default:
echo "无效等级。";
}
// 如果 $grade 是 "A",会输出:表现优异!表现良好。需要努力!
// 如果 $grade 是 "B",会输出:表现良好。需要努力!
// 在函数中使用 switch 和 return (可以省掉 break)
function get_day_name($day_number) {
switch ($day_number) {
case 1: return "星期一";
case 2: return "星期二";
case 3: return "星期三";
case 4: return "星期四";
case 5: return "星期五";
case 6: return "星期六";
case 7: return "星期日";
default: return "无效数字";
}
// 因为所有路径都有 return,这里不可能执行到
}
echo get_day_name(3); // 输出: 星期三
// switch 的一种 "另类" 用法 (不推荐,可读性差)
$input = "start";
switch (true) { // switch 的表达式总是 true
case ($input == "start" or $input == "begin"):
echo "开始了...";
break;
case ($input == "stop" or $input == "end"):
echo "停止了...";
break;
default:
echo "未知命令";
}
// 这种情况下,用 if/elseif 更清晰
Heredoc 和 Nowdoc 语法 (定义多行字符串)
当你需要定义包含很多换行、引号或者特殊字符的长字符串时,用普通引号会很麻烦(需要转义)。这时可以用 Heredoc 或 Nowdoc。语法借鉴自 PHP。
Heredoc (会解析变量)
语法:
$variable = <<<标识符
这里是多行字符串,
可以包含 "引号" 和 '引号',不需要转义。
也可以包含 $变量名,它们会被解析替换。
// 注释也会被包含进去
/* 块注释也行 */
前导空格也会保留。
标识符; // 结束标识符必须顶格写,后面可以紧跟一个分号,不能有其他字符
规则:
以 <<< 开头,后面紧跟一个你自定义的标识符(比如 EOD, HTML, MYTEXT,通常全大写),然后必须换行。
接下来是你的多行字符串内容。
最后,以你之前定义的那个标识符单独一行结束,这一行必须顶格写(前面不能有任何空格或 Tab),标识符后面可以紧跟一个分号 ;,但不能有其他任何字符。
Heredoc 块会覆盖注释,反之亦然,取决于谁先出现。
Heredoc 内部:
换行符、空行、注释都会原样保留。
行首和行尾的空格会保留。
内部的引号不需要转义。
变量会被解析(插值)。
例子:
$name = "12345";
$ai = << 我的名字是 $name, "65 $name"。 // 这里的 $name 会被替换 可以叫我: 65 /* 这是多行 字符串 */ 请注意缩进。 AI_INFO; // 必须顶格 echo $ai; /* 输出会是: 我的名字是 65, "65 12345"。 可以叫我: 65 /* 这是多行 字符串 */ 请注意缩进。 */ 另一种 Heredoc 语法 (需要 # 前缀): 如果你的起始标识符以 # 开头(比如 <<<#MYDATA),那么结束标识符就不必非得顶格写了,可以出现在行内的任何位置,只要它是 标识符# 的形式。 // 传统 Heredoc (结束符必须顶格) $confirm_msg = << 你确定要删除吗? 这个操作无法撤销! MSG; // 使用 # 前缀的 Heredoc (结束符可以在行内) $confirm_msg = <<<#MSG 你确定要删除吗? 这个操作无法撤销!MSG#; // 结束符可以在这里 $isOk = Confirm($confirm_msg); echo $isOk; Nowdoc (不解析变量) Nowdoc 和 Heredoc 非常像,唯一的区别是:Nowdoc 内部的变量不会被解析。它就像单引号字符串的多行版本。 语法: 关键在于起始标识符要用单引号包起来。 $variable = <<<'标识符' 这里是多行字符串。 $变量名 不会被解析。 其他规则和 Heredoc 一样。 标识符; // 结束标识符同样必须顶格写 例子: $type = "Nowdoc"; $text = <<<'EOT' 这是一个 $type 示例。 变量 $type 不会被替换。 EOT; echo $text; /* 输出: 这是一个 $type 示例。 变量 $type 不会被替换。 */ Nowdoc 也支持前面提到的 # 前缀语法(<<<#'标识符'),让结束符可以不用顶格。 解引用运算符 (*) 解引用运算符 * (星号) 可以用在变量名前面,作用是:把这个变量的值当作另一个变量的名字来使用。这在需要动态生成或访问变量名时很有用。 语法: *$变量 例子: $target_var_name = '$user_id'; // $target_var_name 的值是字符串 "$user_id" *$target_var_name = 123; // 这等价于 $user_id = 123; echo $user_id; // 输出: 123 // 也可以用在 perm 或 global 声明中 perm *$target_var_name = 456; // 等价于 perm $user_id = 456; echo $user_id; // 输出: 456 // 也可以用在获取值时 $value = *$target_var_name; // 等价于 $value = $user_id; echo $value; // 输出: 456 // 可以在插值中使用(但默认不行,见下文) // echo "User ID is *$target_var_name"; // 默认会输出 "User ID is *$user_id" // 如果解引用的变量不存在,会发生什么? *$undefined_var = "Hello"; // $undefined_var 不存在,* 就没用了,相当于 $undefined_var = "Hello"; echo $undefined_var; // 输出: Hello 配合 unset, incr, ++/-- 使用: $var = '$a'; *$var = "TEST"; // $a = "TEST" unset *$var; // unset $a; echo $a; // 输出 $a (变量 $a 不存在了) $var = '$counter'; *$var = 10; // $counter = 10 incr *$var; // incr $counter; echo $counter; // 输出 11 *$var = 5; *$var++; // $counter++; echo $counter; // 输出 6 在插值中使用解引用: 默认情况下,*$var 在双引号或 Heredoc 中不会被解引用。你需要使用 aid (Allow Indirect Dereferencing) 命令来临时允许它。 $var = '$message'; *$var = "你好"; echo "The value is: *$var"; // 输出: The value is: *$message aid 1; // 允许解引用插值 echo "The value is: *$var"; // 输出: The value is: 你好 aid 0; // 恢复默认(禁止) // aid 的效果只持续到脚本结束或下次 aid 调用 运算符优先级 运算符优先级决定了在一个包含多个运算符的表达式中,哪个运算先进行。比如 1 + 2 * 3,因为 * 的优先级比 + 高,所以先算 2 * 3,结果是 7,而不是 (1 + 2) * 3 = 9。可以用圆括号 () 强制改变运算顺序。 以下是 XYplorer 脚本中运算符的优先级,从高到低 排列。同一行的运算符优先级相同,按从左到右的顺序计算(例如 3 - 2 + 1 结果是 (3-2)+1 = 2,不是 3-(2+1)=0)。 优先级 运算符 说明 最高 ++ -- 自增, 自减 ! not 逻辑非 + - (一元) 正号, 负号 (如 -5) ^ 乘方 * / *= /= 乘, 除, 乘赋值, 除赋值 % 取模 \ \= 整除, 整除赋值 + - += -= 加, 减, 加赋值, 减赋值 . .= 字符串连接, 连接赋值 < <= > >= == != 比较运算符 Like LikeI UnLike UnLikeI 模式匹配比较 && 逻辑与 ` and 逻辑与 (不区分大小写) xor 逻辑异或 (不区分大小写) or 逻辑或 (不区分大小写) ? : 三元条件运算符 最低 = 赋值 短路 (Short-circuiting): && 和 || 运算符具有短路特性。 对于 A && B,如果 A 为 FALSE,那么整个表达式必定为 FALSE,所以 B 不会被计算或执行。 对于 A || B,如果 A 为 TRUE,那么整个表达式必定为 TRUE,所以 B 不会被计算或执行。 这在某些情况下可以用来避免错误或提高效率,例如 $count != 0 && sum() / $count > 10,如果 $count 是 0,就不会执行后面的除法,避免了除零错误。 远程控制 (主要给开发者) 如果你是软件开发者,你可以通过 Windows 消息机制从你自己的程序向 XYplorer 发送脚本并执行。 使用 WM_COPYDATA 消息发送给 XYplorer 的主窗口句柄 (hWnd)。 COPYDATASTRUCT 结构体设置如下: dwData: 设置为 4194305 (十六进制 0x00400001)。 lpData: 指向一个包含脚本的字符串。这个字符串的格式和命令行参数 /script= 完全一样: 可以是一个 .xys 脚本文件的完整路径。 也可以是脚本代码本身,但代码前必须加上 :: 前缀。 这样,你就可以用你熟悉的编程语言来控制 XYplorer 完成各种任务了。 用户自定义函数 (User-Defined Functions) 就像很多编程语言一样,你可以创建自己的函数,把常用的代码块封装起来,方便重复调用。这也让你的脚本更模块化、更易读。语法也和 PHP 很像。 定义函数: function 函数名([参数1], [参数2=默认值], [&参数3], ...) { // 函数体代码 // ... return 返回值; // 可选,用 return 返回结果 } 规则: 以 function 关键字开头,后面跟一个空格,然后是函数名。 函数名 规则:只能包含字母 (a-z, A-Z)、数字 (0-9) 和下划线 (_),且不能以数字开头。 函数名是不区分大小写的!MyFunc 和 myfunc 是同一个函数。 函数名后面是圆括号 (),里面可以定义参数列表,参数用逗号分隔。 函数体代码放在花括号 {} 里。 function 定义可以放在脚本文件的任何地方(主脚本之前、之后、中间),可以缩进也可以不缩进。 定义函数不会立即执行它。你需要像调用内置函数一样调用它才能执行。 所有用户定义的函数都具有全局作用域,一旦定义,在整个脚本执行期间(包括被 load 或 sub 调用的其他脚本)都可以调用。 用户函数会覆盖同名的内置函数!请小心命名。 如果定义了多个同名的用户函数,只有第一个定义的会生效,后面的同名定义会被忽略。不支持函数重载或重新定义。 函数可以相互调用。 支持递归调用(函数调用自身),但要注意递归深度,太深可能导致堆栈溢出而脚本终止。 参数传递: 默认是按值传递 (Pass by Value)。函数内部对参数的修改不会影响调用者那边的原始变量。 如果想按引用传递 (Pass by Reference),让函数能够修改调用者的变量,在函数定义时,在参数名前加上 & 符号。 参数可选与默认值: 所有参数都是可选的。如果在调用函数时省略了某个参数,它在函数内部的值会是空字符串 "" (除非你设置了默认值)。 可以在函数定义时给参数设置默认值,使用 = 符号。例如 function myFunc($p1, $p2 = "default")。如果调用时没提供 $p2,它就会使用 "default"。 带有默认值的参数必须放在没有默认值的参数之后。 默认值可以是字面量,也可以是未加引号或双引号的 XYplorer 变量 (如 例子 1:基本参数和返回值 // 定义函数 function multiply($x, $y) { return $x * $y; // 返回乘积 } function add($a, $b) { $sum = $a + $b; return $sum; // 返回和 } // 调用函数 $result1 = multiply(3, 4); // 12 $result2 = add(11, 12); // 23 echo $result1 . 例子 2:按值传递 (默认) function try_add_one($num) { $num++; // 修改的是函数内部的副本 echo "函数内部: " . $num; } $original = 1; try_add_one($original); // 输出: 函数内部: 2 echo "函数外部: " . $original; // 输出: 函数外部: 1 (原始值没变) 例子 3:按引用传递 (&) function really_add_one(&$num) { // 注意这里的 & $num++; // 修改的是调用者的原始变量 echo "函数内部: " . $num; } $original = 1; really_add_one($original); // 输出: 函数内部: 2 echo "函数外部: " . $original; // 输出: 函数外部: 2 (原始值被修改了!) Include 语句 include 语句允许你将另一个文件的内容包含到当前脚本中,就好像那些内容直接写在 include 的位置一样。这对于组织代码、创建可重用的函数库非常有用。 重要: include 语句是在脚本资源加载时、在执行任何其他代码之前就被处理的。 语法: include 文件路径; 文件路径: 如果是相对路径或只有文件名,会相对于 XYplorer 的 脚本文件夹 ( 扩展名默认为 .xys。写 include "mylib" 和 include "mylib.xys" 效果一样。 路径可以用引号包起来(单双都行),纯粹是为了好看,功能上没区别。 注意: 你不能在 文件路径 中使用脚本变量 ($var)。但是,可以使用 XYplorer 变量 ( 语句末尾的分号 ; 是可选的。 include 语句必须自己单独占一行,后面不能跟其他命令。 其他说明: 嵌套包含: 被包含的文件本身也可以包含其他文件。最大嵌套深度是 100 层。 递归包含: 小心不要让文件 A 包含文件 B,而文件 B 又包含文件 A(或形成更长的循环)。这会导致无限递归,很快就会达到 100 层嵌套限制而报错。 缩进继承: 如果 include 语句本身是缩进的,那么被包含进来的整个文件内容也会保持相对于该 include 语句的缩进。 例子: 假设你有一个 math_lib.xys 文件在 // math_lib.xys function add($a, $b) { return $a + $b; } function subtract($a, $b) { return $a - $b; } 然后你的主脚本 main_script.xys 可以这样写: // main_script.xys include "math_lib"; // 包含库文件 (会自动找 math_lib.xys) "测试加法" $result = add(5, 3); echo "5 + 3 = " . $result; "测试减法" $result = subtract(10, 4); echo "10 - 4 = " . $result; 当你运行 main_script.xys 时,math_lib.xys 里的函数就可以直接使用了。 Include_once 语句 include_once 和 include 几乎完全一样,唯一的区别是:它会检查指定的文件是否已经被包含过。如果已经被包含过(通过 include 或 include_once),include_once 语句就会被直接忽略,不会再次包含,也不会报错。 这在复杂项目中很有用,可以避免因为不小心多次包含同一个文件而导致的函数重复定义等问题。 语法: include_once 文件路径; 规则和 include 相同。 自动包含 (Auto Include) 有一个特殊机制,可以让某些脚本(主要是用户函数库)在你从地址栏运行脚本时自动被包含进来,这样你就可以在地址栏直接调用自定义函数了,而不需要每次都写 include。 方法: 在你的 XYplorer 脚本文件夹 ( 把你想在地址栏方便使用的用户函数定义写在这个文件里。例如:// xy-autoinclude.xys function half($a) { return $a / 2; } function welcome($name = "朋友") { return "欢迎你, " . $name . "!"; } 保存文件。 现在,你就可以直接在 XYplorer 的地址栏输入并执行: ::echo half(10); (回车后会显示 5) ::echo welcome("管理员"); (回车后会显示 “欢迎你, 管理员!”) ::echo welcome(); (回车后会显示 “欢迎你, 朋友!”) 注意: XYplorer 只在每次会话 (session) 中第一次尝试从地址栏运行脚本时检查 xy-autoinclude.xys 文件是否存在。如果第一次没找到,那么在这次会话期间就不会再尝试加载它了(为了效率)。如果你创建或修改了 xy-autoinclude.xys,需要重启 XYplorer 才能让它在地址栏生效。 ”高级“功能 通过命令行访问 /exp 参数 作用: 确保 XYplorer 启动时,指定的那个文件夹在左侧的目录树里是展开状态,方便你一眼看到它的子文件夹。 示例:XYplorer.exe /exp # 展开默认启动文件夹 XYplorer.exe /path=C:\ /exp # 打开 C 盘根目录,并展开它 /feed 参数 作用: 允许你把一段脚本给一个已经运行的 XYplorer 实例运行,而且不会改变那个实例当前打开的位置或标签页。可以看作是 /script 和 /flg=2 两个参数的便捷组合。 注意: 如果你同时用了 /script 和 /feed,那么 /feed 的内容会覆盖 /script 的。 /flg 参数 作用: 这个参数带有一些“标志位”,用来控制特殊行为。 /flg=2: 配合 /script 参数使用时,它告诉 XYplorer 把脚本给已存在的实例,并且不改变该实例当前的位置或标签。 (和 /feed 的核心功能类似) XYplorer.exe /script="::msg 'Hi!';" /flg=2 /flg=8: 启动 XYplorer 时,禁止执行任何“自定义列”脚本。这在你不小心写错了自定义列脚本导致 XYplorer 无法正常启动时,可以救你一命。 /fresh 参数 作用: 除了许可证信息,此模式不会加载任何你的个人设置(配置、历史记录等)。这对于排查问题特别有用,可以看看在“出厂设置”下问题是否还存在。 /hwnd 参数 作用: 当你使用 /script 或 /feed 向一个已存在的 XYplorer 实例发送脚本时,如果你知道那个目标窗口的句柄(HWND,一个窗口的唯一标识符),可以用这个参数精确指定目标。 示例(在 XYplorer 脚本中): 如果你想把脚本发送给当前这个 XYplorer 窗口,可以用内置变量 这里的 /ini 参数 作用: 指定 XYplorer 启动时加载哪个 .ini 配置文件。默认是 XYplorer.ini。 用法: /ini=myconfig 或 /ini=myconfig.ini:加载位于“应用程序数据路径”下的 myconfig.ini 文件。 /ini="C:\My Settings\myconfig.ini":加载指定完整路径的配置文件。 /ini=C:\XYdata\ (注意末尾的反斜杠):将 C:\XYdata\ 设置为“应用程序数据路径”,并加载该路径下的默认 XYplorer.ini 文件。 /new 参数 作用: 强制打开一个新的 XYplorer 窗口,无视任何可能阻止多实例的设置。 示例:XYplorer.exe /new /path 参数 作用: 明确指定 XYplorer 启动后应该打开的路径。 示例:XYplorer.exe /path=C:\ XYplorer.exe /path="C:\Program Files" # 路径有空格,用引号 注意: 你也可以不使用 /path 参数,直接把路径放在命令行的最后(见后面的“设置启动路径”部分)。但如果同时存在,/path 参数指定的路径会优先于那个放在最后的路径。 /readonly 参数 作用: 以只读模式启动 XYplorer。它会读取磁盘上的设置,但绝不会将任何更改写回磁盘。这样,你在这个实例中所做的任何配置改动(比如调整视图、修改设置)都不会影响你保存在硬盘上的原始配置。 示例:XYplorer.exe /readonly 在只读模式下,窗口标题栏会显示 [READONLY] 字样。 如果你在只读模式下尝试保存设置(例如点击“配置”窗口的“确定”),状态栏会给出提示。 /script 参数 作用: 让 XYplorer 在启动时直接运行一段脚本。 用法: /script=[脚本来源],这里的 [脚本来源] 可以是: 一个脚本文件的路径(通常是 .xys 文件)。路径解析规则和 load 脚本命令类似,可以省略 .xys 扩展名。如果脚本文件在默认的脚本文件夹 ( 示例:运行 示例:运行指定路径的脚本(路径含空格需加引号)XYplorer.exe /script="C:\My Scripts\do this.xys" 直接写脚本代码。代码必须以 :: 开头,并且不能包含双引号或其他可能干扰命令行解析的特殊字符。 示例:弹出一个消息框XYplorer.exe /script="::msg 'Welcome to XY!';" 注意:因为脚本代码里有空格,所以整个 ::... 部分需要用双引号包起来。 如果脚本需要用到双引号怎么办? 可以使用 quote() 函数或者 runq 配合单引号:XYplorer.exe /script="::run quote('E:\Test\Has Space.txt');" XYplorer.exe /script="::runq 'E:\Test\Has Space.txt';" /select 参数 作用: 让 XYplorer 打开指定项的父目录,并在文件列表中选中该项。 示例: 打开 C 盘根目录,并选中 Windows 文件夹。XYplorer.exe /select=C:\Windows /title 参数 作用: 为当前 XYplorer 会话设置一个自定义标题。如果标题包含空格,需要用引号括起来。 示例: /title="Project 6512345" /user 参数 作用: 允许你通过命令行传递一些自定义的值给 XYplorer。这些值用 | 分隔,整个列表可以用引号包起来(可选)。之后你可以在 XYplorer 脚本中通过 get("CmdLineUser", index) 来获取这些值。 示例: 命令行调用:XYplorer.exe /user=value1|value2|some value3 XYplorer.exe /user="value1|value2|some value3" # 加引号效果一样 在 XYplorer 脚本中获取:echo get("CmdLineUser"); // 输出: value1|value2|some value3 echo get("CmdLineUser", 1); // 输出: value1 /win 参数 (基础用法) 作用: 控制 XYplorer 启动时的窗口状态。 选项: /win=min:启动后最小化。 /win=max:启动后最大化。 /win=normal:启动后是普通窗口状态。 /win=tray:启动后直接最小化到系统托盘区。 扩展用法 除了控制窗口状态,还可以指定窗口启动时的位置和尺寸,覆盖掉保存在 INI 文件里的值。 格式: /win=[状态],[X坐标],[Y坐标],[宽度],[高度] [状态] 可以是 min, max, normal, tray 之一。 [X坐标], [Y坐标], [宽度], [高度] 是像素值。 所有值都是可选的,如果省略某个值,则会使用 INI 文件中记录的对应值。 示例: 普通状态,位置 (40, 20),尺寸 1200x800:/win=normal,40,20,1200,800 状态和高度用 INI 里的值,指定位置 (20, 20) 和宽度 1200:/win=,20,20,1200 启动到系统托盘,并设定好恢复后的位置和尺寸:/win=tray,40,20,1200,400 Get命令 点我跳转 自定义文件打开方式 (WIP) Hamburger 可以自定义右键菜单 菜单命令 菜单命令(这里的“菜单”指的是 XYplorer 窗口的主菜单)通过其唯一的命令 ID (CID) 来引用,并以 # 作为前缀。你可以在菜单中直接显示这些命令 ID,只需勾选这个开关即可:菜单 帮助 | 菜单显示命令 ID。 通用格式: #CID[;标题;图标;状态] 例如: #101 默认情况下,上述定义将创建这样一个菜单项:项目路径/名称 Ctrl+P 点击该项会触发相应的命令,效果完全等同于你点击了原始的主菜单项:文件 | 到剪贴板 | 项目路径/名称。 (可选) 你也可以指定自定义的标题和图标,用分号分隔,例如: #101;复制些东西;copy.ico 状态(State): 此处及下文所有地方,可选的状态字段是一个位字段,允许你使用以下这些“位”(bit)来修改每个菜单项的状态: 1 = 默认项(显示为粗体) 2 = 选中状态(显示复选标记) 4 = 禁用状态(显示为灰色且不可点击) 这些值可以相加。例如,要使项目同时为粗体并被选中 (1+2=3): #101;复制些东西;copy.ico;3 工具栏按钮 工具栏按钮通过其唯一的key引用,以 : 作为前缀。在工具栏上按住 CTRL 键并将鼠标悬停在按钮上。或者,按住 CTRL 键的同时点击菜单 工具 | 自定义工具栏... (快捷键 Ctrl+Shift+F9);按钮键会显示在每个按钮标题的旁边。 通用格式: :key[;标题;图标;状态] 例如: :dice 默认情况下,上述定义将创建随机排序 Ctrl+Alt+R` 点击该项会触发与点击工具栏按钮本身相同的操作。 (可选) 你也可以指定自定义的标题和图标,用分号分隔,例如: :dice;随机排序;E:\pics\65.png 注意: 具有“按下”状态的工具栏按钮,如果当前正处于按下状态,则在菜单项旁边会显示 [On]。 路径 通用格式: 路径[;标题;图标;状态] 只需直接粘贴路径即可。例如: C:\Program Files (x86)\XYplorer 默认情况下,上述定义将创建此菜单项:XYplorer 点击该项将会执行以下操作之一: 打开一个文件夹 运行一个可执行文件 使用关联的程序打开任何其他类型的文件 支持 XYplorer 的原生变量和环境变量,例如: 或 %user% (可选) 你也可以指定自定义的标题和图标,用分号分隔,例如: C:\;65.jpg Paper Folders和虚拟文件夹(Virtual Folders)也可以作为路径使用: vi: paper:图片 URL 通用格式: url[;标题;图标;状态] 只需直接粘贴 URL 即可。例如: https://www.xyplorer.com 默认情况下,上述定义将创建此菜单项:https://www.xyplorer.com 点击该项将在系统关联的默认浏览器中打开该 URL。 (可选) 你也可以指定自定义的标题和图标,用分号分隔,例如: https://www.xyplorer.com;XY官网;fullofbugs.ico 脚本 通用格式: ::脚本; 或 ::标题;脚本; 或 ::标题;/图标;脚本; 在 Hamburger 菜单中使用的脚本必须以 :: 作为前缀。例如: ::echo "你好!"; 默认情况下,上述定义将创建此菜单项:echo "你好!"; 点击该项将运行此脚本(关于脚本语法的详细信息,请参阅“脚本编写”相关文档)。 (可选) 你可以在脚本内容前指定一个自定义标题,用分号分隔,例如: ::问候56;echo "65!"; (可选) 你还可以在自定义标题后添加一个自定义图标,图标路径前缀为 /,例如: ::问候65;/not65.ico;echo "65!"; 菜单整体语法 只需每行定义一个菜单项,你就定义了一个菜单。你可以自由地混合使用所有类型的菜单项。还可以选择性地加入一些 - 作为菜单分隔符。例如: #101 :dice - C:\Program Files (x86)\XYplorer https://www.xyplorer.com - ::问候65;echo "65!"; 当在脚本命令 popupmenu 和 popupnested 中使用时,你可以将所有菜单项定义压缩到一行中,并使用你选择的字符作为分隔符。 嵌套(子菜单) Hamburger 菜单以一种完全直观的方式支持嵌套子菜单。只需将希望放入子菜单的项目进行缩进即可。 注释 可以在每个菜单项定义的末尾添加注释,注释内容前需要有 //。例如: 也可以通过在项目定义的最前面放置 // 来隐藏某个菜单项(使其不显示在菜单中): // 显式 Hamburger 标记 在极少数情况下,解析器可能无法自动识别一个定义是用于 Hamburger 菜单的。这时,可以在定义的第一行放置 //H 来明确地将其标记为 Hamburger 菜单定义。 部分翻译自XYPlorer官方文档