--- title: 在 ssh-blog 里使用 Monkey date: 2026-10-21 tags: monkey, ssh-blog, 终端 summary: 浏览器终端、SSH 交互、一次性命令、管道和重定向——这个站点里调用 Monkey 的几种方式 --- # 在 ssh-blog 里使用 Monkey `bin/monkey` 是本站在 `bin/` 里自己放的一个程序,不是 ssh-blog 框架自带的命令。对访客来说,它和普通命令一样:输入名字就能跑,也可以接管道、重定向。 ## 浏览器终端 打开首页,在提示符后面输入: ```console visitor@localhost:/$ monkey ``` 终端就交给了解释器。之后每行输入一条完整的 Monkey 代码: ```monkey let square = fn(x) { x * x }; map([1, 2, 3, 4], square) ``` ```text [1, 4, 9, 16] ``` 退出方式: - 输入 `@@`; - 或者按 Ctrl-D; - Ctrl-C 直接中断解释器,回到伪 bash(`$?` 会变成非 0)。 解释器运行在服务端。刷新或关闭页面、空闲 5 分钟,进程都会被收掉,REPL 里的变量和宏不会保留。 ## SSH 交互 按首页横幅里的提示 ssh 进来,然后和浏览器里一样: ```console $ ssh -p 443 你的站点 visitor@localhost:/$ monkey ``` 网页和 SSH 交互会话都会分配 pty,所以提示符、回显、Ctrl-C / Ctrl-D 都正常。 ## 一次性命令 ```console $ ssh -p 443 你的站点 'monkey -e "1 + 1"' 2 $ ssh -p 443 你的站点 'monkey -e "map([1, 2, 3, 4], fn(x) { x * x })"' [1, 4, 9, 16] ``` 没有申请 pty 时,解释器自动进入批处理:没有横幅、没有 `>> `,只输出结果,适合放进脚本。加 `-t` 可以强制走交互模式。 ## 管道和重定向 Monkey 在伪 bash 里就是一个普通命令: ```console visitor@localhost:/$ echo "1 + 1" | monkey 2 visitor@localhost:/$ monkey -e "map([1, 2, 3], fibonacci)" | cat [1, 1, 2] ``` 写到文件: ```console visitor@localhost:/$ monkey -e "let a = 3; a" > out.txt visitor@localhost:/$ cat out.txt 3 ``` 注意 `let` 只是赋值,没有值: ```console visitor@localhost:/$ monkey -e "let a = 3" > empty.txt visitor@localhost:/$ cat empty.txt ``` 这里不会打印任何东西,`empty.txt` 是 0 字节。这和在 REPL 里输入 `let a = 3;` 不打印结果是一致的;想输出值就写 `let a = 3; a`。 `>` 写的是你自己的虚拟视图,不碰服务器磁盘。刷新页面或者 `reset` 之后,`out.txt` 就没了。 退出码也会传回来: ```console visitor@localhost:/$ monkey -e "nope" Identifier not found: nope visitor@localhost:/$ echo $? 1 ``` 伪 bash 的 `$?` 只区分 0 和非 0。 ## 跑脚本 仓库里有一个可以直接运行的示例: ```console visitor@localhost:/$ cat posts/monkey/demo.monkey visitor@localhost:/$ monkey posts/monkey/demo.monkey 120 [1, 4, 9, 16, 25] 55 15 ``` 路径按当前目录算:上面的命令是在 `/` 下写的;如果已经 `cd posts/monkey`,就改成 `monkey demo.monkey`。 `monkey` 是外部程序,文件参数由它自己按真实工作目录打开;伪 bash 里的 `/posts/...` 这种虚拟绝对路径只对内置命令有效。所以在哪个目录,就用相对那个目录的路径最稳。 交互模式按行解析,多行函数要写在一行里;多行程序放进脚本文件,用 `monkey 文件` 运行最省事。 ## 案例文件 `posts/monkey/` 下有几份 `.txt`,每一份开头都用 `//` 注释写了运行方式。它们既是网页上的纯文本,也是可以直接执行的 Monkey 脚本。表格里的命令假设当前在 `/`;如果已经 `cd posts/monkey`,把 `posts/monkey/` 前缀去掉: | 文件 | 内容 | 运行 | |---|---|---| | `case_function.txt` | 函数、闭包、递归 | `monkey posts/monkey/case_function.txt` | | `case_collection.txt` | 数组、哈希、高阶函数 | `monkey posts/monkey/case_collection.txt` | | `case_macro.txt` | 宏 `unless` / `when` | `monkey posts/monkey/case_macro.txt` | | `case_pipeline.txt` | 把输出交给管道和重定向 | `monkey posts/monkey/case_pipeline.txt` | 网页上可以直接打开 `/posts/monkey/case_function.txt` 读源码,终端里 `cat` 同一份文件,`monkey` 读它执行。输出都可以继续接 `| head`、`| grep`、`| wc`,或者 `> report.txt`。 ## 命令行参数 ```text monkey [选项] [脚本] -e 代码 求值一段代码后退出 -q 不打印开场横幅 -v 显示版本 ``` ```console visitor@localhost:/$ monkey -v monkey 1.0.0 ``` 不给脚本和 `-e` 时读标准输入:标准输入是终端就是交互式 REPL,否则逐行批处理。 ## 和伪 bash 的其他配合 - `help` 里有一组“程序”,列出 `bin/` 下可运行的文件; - `which monkey` 会告诉你它是外部程序,以及文件在仓库里的位置; - `man monkey` 给出外部程序的简要说明; - Tab 补全会把 `monkey` 算进候选。 它不是 ssh-blog 的内置命令。换一份 ssh-blog 部署,需要自己把程序放进那棵树的 `bin/` 里;程序需要满足的接口见仓库里的 `bin/README.md`。