visitor@wangyvdi.top:~$ cat posts/monkey/03_在_ssh_blog_里用_monkey.md

在 ssh-blog 里使用 Monkey

#monkey #ssh-blog #终端 3 min

bin/monkey 是本站在 bin/ 里自己放的一个程序,不是 ssh-blog 框架自带的命令。对访客来说,它和普通命令一样:输入名字就能跑,也可以接管道、重定向。

浏览器终端

打开首页,在提示符后面输入:

visitor@localhost:/$ monkey

终端就交给了解释器。之后每行输入一条完整的 Monkey 代码:

let square = fn(x) { x * x };
map([1, 2, 3, 4], square)
[1, 4, 9, 16]

退出方式:

  • 输入 @@;
  • 或者按 Ctrl-D;
  • Ctrl-C 直接中断解释器,回到伪 bash($? 会变成非 0)。

解释器运行在服务端。刷新或关闭页面、空闲 5 分钟,进程都会被收掉,REPL 里的变量和宏不会保留。

SSH 交互

按首页横幅里的提示 ssh 进来,然后和浏览器里一样:

$ ssh -p 443 你的站点
visitor@localhost:/$ monkey

网页和 SSH 交互会话都会分配 pty,所以提示符、回显、Ctrl-C / Ctrl-D 都正常。

一次性命令

$ 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 里就是一个普通命令:

visitor@localhost:/$ echo "1 + 1" | monkey
2

visitor@localhost:/$ monkey -e "map([1, 2, 3], fibonacci)" | cat
[1, 1, 2]

写到文件:

visitor@localhost:/$ monkey -e "let a = 3; a" > out.txt
visitor@localhost:/$ cat out.txt
3

注意 let 只是赋值,没有值:

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 就没了。

退出码也会传回来:

visitor@localhost:/$ monkey -e "nope"
Identifier not found: nope
visitor@localhost:/$ echo $?
1

伪 bash 的 $? 只区分 0 和非 0。

跑脚本

仓库里有一个可以直接运行的示例:

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。

命令行参数

monkey [选项] [脚本]
  -e 代码   求值一段代码后退出
  -q        不打印开场横幅
  -v        显示版本
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。

在终端里读这篇:ssh -p 2022 wangyvdi.top cat posts/monkey/03_在_ssh_blog_里用_monkey.md (原文 是同样的纯文本)