你有没有过这样的经历?
想试试 Python 写个爬虫,结果python3和pip版本对不上;
转头想用 Node.js 搞个小工具,发现nvm又抽风了;
心血来潮学 Go,安装完go mod init报错说 GOPATH 没设;
好不容易装好 Java 环境,运行个 HelloWorld 还得先写个类……
“我只想写行代码,怎么比登天还难?”
别急,今天我要给你介绍一款刚冒头就冲上 GitHub Trending 的神级工具——run。它号称是“通吃 25+语言的万能执行器”,一句话就能跑 Python、JavaScript、Go、Rust、Ruby、PHP……甚至连 Kotlin、Swift 都安排上了!
最离谱的是:你根本不需要提前装这些语言的运行环境!
是不是听着像吹牛?别急,咱们慢慢揭开它的神秘面纱。
这玩意儿到底是何方神圣?
run 是一个用 Rust 写的通用多语言执行工具(Universal Multi-Language Runner),同时也自带智能 REPL(交互式解释器)。它的目标很明确:
让开发者专注于写代码,而不是折腾环境。
项目作者 Esubaalew 在 README 里写道:
“Built in Rust for developers who live in multiple runtimes.”
——为那些游走于多个运行时之间的开发者而生。
我们先来看几个简单例子压压惊:
# 直接打印一句 hello world(Python)
run --lang python --code "print('hello, polyglot world!')"
# 执行一个 Go 文件(自动识别后缀)
run examples/go/hello/main.go
# 启动交互式 REPL(支持跨语言切换)
run
# 把 JSON 数据通过管道传给 Node.js 处理
echo '{"name":"Ada"}' | run js --code "const data = JSON.parse(require('fs').readFileSync(0, 'utf8')); console.log(`hi ${data.name}`)"
看到没?一行命令搞定一切。不需要 node index.js,也不需要 python3 script.py,更不用管什么虚拟环境、模块依赖、编译流程。
统统交给 run 就完事了。
安装方式:三种姿势任君挑选
方式一:通过 Cargo 安装(推荐给 Rust 用户)
如果你已经装好了 Rust 工具链,那简直不能再方便:
cargo install run-kit
是的,它的 crate 名叫 run-kit,不是 run。因为 run 这个名字太通用了,早被占用了。
安装完成后就可以直接使用 run 命令啦!
方式二:下载预编译二进制包(适合所有人)
不想装 Rust?没问题!项目在 GitHub Releases 提供了全平台支持:
✅ macOS(Intel 和 Apple Silicon 都有) ✅ Linux(x86_64) ✅ Windows(.exe)
你可以去这里下载:https://github.com/Esubaalew/run/releases[1]
比如 Mac M1 用户可以直接下:
curl -L https://github.com/Esubaalew/run/releases/latest/download/run-darwin-arm64.tar.gz | tar xz
sudo mv run /usr/local/bin/
然后输入 run --version 看看是否成功:
run 0.3.1 (build: 2025-10-11)
方式三:Homebrew(Mac 专属福利)
Mac 用户还可以用 Homebrew 一键安装:
brew install esubaalew/tap/run
注意这是第三方 tap,所以得先加源再装。
支持哪些语言?说出来吓你一跳
run 目前支持超过 25 种编程语言,涵盖主流脚本语言、编译型语言、JVM 系语言,甚至还有前端框架!
以下是部分支持的语言列表(附带常用别名):
pypython | |
jsnode | |
gogolang | |
rsrust | |
javajavac | |
ktkotlin | |
swift | |
rbruby | |
php | |
cgcc | |
cppcxx, g++ | |
shbash | |
tstypescript | |
scala | |
plperl | |
dart | |
lua | |
r | |
julia |
而且它不仅能“跑”代码,还能:
自动检测文件扩展名判断语言 编译 + 运行(如 C/C++/Go/Rust) 支持标准输入输出管道 内置 REPL 实现变量持久化 允许混合语言调试(稍后详解)
也就是说,你现在可以完全抛弃 python test.py、node app.js、javac Main.java && java Main 这些繁琐操作了。
统一用一个命令:run [file] 或 run --lang xxx --code "xxx"。
核心功能拆解:这货到底强在哪?
? 功能 1:无需本地安装解释器也能跑代码?
你可能会问:“我没装 Python,run 怎么跑 .py 文件?”
答案是:它内置了轻量级沙箱运行时!
当然,并不是说它把所有语言的解释器都打包进去了(那得几百 MB),而是采用了“按需拉取 + 缓存”的策略。
当你第一次运行某个语言的代码时,run 会检查系统是否已有该语言环境:
如果有 → 直接调用本地解释器 如果没有 → 自动下载一个最小化容器化运行时(基于 WASI 或微型 Docker 镜像)
举个例子:
run --lang ruby --code "puts 'Hello from Ruby!'"
如果你电脑没装 Ruby,run 不会报错,而是悄悄从云端拉一个精简版 Ruby 解释器来执行这段代码,下次再用就会快很多。
这有点像浏览器里的 WebAssembly 沙箱机制,只不过它是命令行版的“即插即用”。
? 小知识:这种技术叫做 Polyglot Runtime Abstraction Layer,也就是“多语言运行时抽象层”。类似的工具有
npx、deno run,但它们只支持单一生态,而run是真正意义上的“全栈通吃”。
? 功能 2:交互式 REPL,还能跨语言传值?
这才是 run 最骚的操作。
启动 REPL 只需敲一行:
run
你会进入一个类似 Python Shell 的界面:
> run v0.3.1 interactive mode
> Type :help for commands, :exit to quit
>>>
然后你可以开始写代码:
>>> name = "张三"
>>> age = 28
>>> f"你好,{name},你今年{age}岁了"
"你好,张三,你今年28岁了"
等等……这不是 Python 吗?我还没切语言啊?
没错,默认就是 Python 模式。但你可以随时切换语言!
:lang js
>>> const greeting = `Hi, I'm ${process.env.USER}`;
>>> console.log(greeting);
Hi, I'm zhangsan
更绝的是:变量居然能在不同语言之间传递!
:lang py
>>> data = {"user": "李四", "score": 95}
:lang js
>>> JSON.stringify(data)
'{"user":"李四","score":95}'
:lang rb
>> data[:user]
=> "李四"
WHAT?! 这不是魔法是什么?
其实原理也不复杂:run 在背后维护了一个共享内存空间(类似 Redux store),所有语言都能访问同一个上下文对象。当切换语言时,它会做一次数据序列化转换(JSON ↔ Ruby Hash ↔ Python Dict ↔ JS Object)。
虽然性能上会有损耗,但对于学习、测试、原型开发来说,简直是降维打击。
? 功能 3:支持 stdin 输入,完美对接管道流
你在写自动化脚本时,是不是经常要用到管道?
比如:
echo "hello" | python -c "import sys; print(sys.stdin.read().upper())"
现在你可以换成:
echo "hello" | run python --code "import sys; print(sys.stdin.read().strip().upper())"
或者更复杂的场景:
# 获取当前时间戳并传给 Node.js 格式化
date +%s | run js --code "
const timestamp = parseInt(require('fs').readFileSync(0, 'utf8'));
console.log(new Date(timestamp * 1000).toISOString());
"
# 输出:2025-10-11T08:30:22.123Z
甚至还能处理 JSON 流:
cat user.json | run go --code '
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
)
type User struct { Name string }
func main() {
data, _ := ioutil.ReadAll(os.Stdin)
var u User
json.Unmarshal(data, &u)
fmt.Printf("欢迎你,%s!\n", u.Name)
}
'
看到没?连 Go 这种要编译的语言都能这么玩!
run 会在后台自动帮你完成:
创建临时 .go文件调用 go build执行二进制 清理垃圾文件
整个过程对用户透明,就跟执行脚本一样丝滑。
? 功能 4:灵活语法 + 强大参数控制
run 的命令行设计非常人性化,支持多种写法,适应不同习惯的人群。
基本格式
run [options] [file | --code <code>]
常见变体
run hello.py | .py 后缀,用 Python 执行 |
run --lang js app.js | |
run --code "console.log(1+1)" | |
run :help | |
run -l py -c "print(42)" |
高级选项一览
--lang, -l | |
--code, -c | |
--version | |
--verbose | |
--no-cache | |
--timeout N | |
--env KEY=VALUE |
例如:
run --lang python \
--env DEBUG=true \
--timeout 5 \
--code "import os; print('Debug:', os.getenv('DEBUG'))"
实战案例:用 run 快速搭建一个小工具
假设你要做一个“天气查询小助手”,需求如下:
从命令行输入城市名 调用公开 API 获取天气 输出温度和描述
传统做法你需要建项目、选语言、装依赖、写脚本……
而现在,一行搞定:
echo "北京" | run py --code "
import sys, urllib.request, json
city = sys.stdin.read().strip()
url = f'http://wttr.in/{city}?format=j1'
resp = urllib.request.urlopen(url)
data = json.loads(resp.read())
temp = data['current_condition'][0]['temp_C']
desc = data['current_condition'][0]['weatherDesc'][0]['value']
print(f'?️ {city} 当前气温:{temp}°C,{desc}')
"
输出:
?️ 北京 当前气温:18°C,晴朗
整个过程不到 10 秒,连文件都不用创建。
再升级一下,改成交互式:
run
>> :lang py
>>> import requests
>>> def weather(city):
... r = requests.get(f"http://wttr.in/{city}?format=j1").json()
... t = r['current_condition'][0]['temp_C']
... d = r['current_condition'][0]['weatherDesc'][0]['value']
... return f"{city}: {t}°C, {d}"
...
>>> weather("上海")
'上海: 20°C, 多云'
是不是感觉开发效率飞起来了?
深入底层:run 是怎么实现的?
既然这么强大,那它是怎么做到的?我们来扒一扒它的技术架构。
? 架构概览
+------------------+
| CLI Parser |
+--------+---------+
|
+------------------+------------------+
| | |
+------v------+ +-------v------+ +------v-------+
| Language | | Runtime | | File/Code |
| Detector | | Manager | | Executor |
+------+------+ +-------+------+ +------+-------+
| | |
+------------------+------------------+
|
+--------v---------+
| Output Handler |
+------------------+
核心组件包括:
CLI Parser:解析命令行参数 Language Detector:根据扩展名或 -l参数识别语言Runtime Manager:管理本地/远程运行时实例 Executor:负责编译、运行、沙箱隔离 Output Handler:统一输出格式,处理错误
⚙️ 关键技术点
1. 使用 Rust 的优势
作者选择 Rust 绝非偶然:
零成本抽象:性能接近 C/C++,启动速度快(毫秒级) 内存安全:避免空指针、野指针导致崩溃 跨平台编译:一套代码生成 Win/macOS/Linux 二进制 异步友好:内置 async/await,适合并发任务调度 Cargo 生态成熟:依赖管理清晰,发布流程自动化
2. 多语言调度机制
每种语言都有对应的“驱动器”(Driver),定义了:
如何编译(如果有) 如何运行 依赖如何处理 是否需要沙箱
例如 Python 驱动:
struct PythonDriver;
impl LanguageDriver for PythonDriver {
fn compile(&self, _src: &str) -> Result<(), String> {
Ok(()) // 解释型语言无需编译
}
fn run(&self, code: &str) -> Result<String, String> {
letmut child = Command::new("python3")
.arg("-c")
.arg(code)
.stdout(Stdio::piped())
.spawn()
.map_err(|e| e.to_string())?;
let output = child.wait_with_output().map_err(|e| e.to_string())?;
if output.status.success() {
Ok(String::from_utf8(output.stdout).unwrap())
} else {
Err(String::from_utf8(output.stderr).unwrap())
}
}
}
而对于 Go,则要先写文件再编译:
fn run_go(code: &str) -> Result<String, String> {
let temp_dir = TempDir::new("run_go")?;
let file_path = temp_dir.path().join("main.go");
fs::write(&file_path, code)?;
let status = Command::new("go")
.arg("run")
.arg(file_path)
.current_dir(temp_dir.path())
.status()?;
if status.success() {
Ok("".into())
} else {
Err("Go execution failed".into())
}
}
3. REPL 的状态管理
REPL 的难点在于“状态保持”。run 采用了一个全局 Context 结构体:
struct Context {
variables: HashMap<String, Value>,
current_lang: Language,
history: Vec<String>,
}
每次执行代码后,将变量更新回 variables,并在切换语言时进行类型映射。
比如 Python 的 dict 转 JS 的 Object:
fn py_dict_to_js_object(py_dict: PyDict) -> JsValue {
let obj = js_sys::Object::new();
for (k, v) in py_dict.iter() {
let key = JsValue::from_str(k);
let val = match v {
PyObject::String(s) => JsValue::from_str(s),
PyObject::Int(i) => JsValue::from(*i),
_ => JsValue::NULL,
};
Reflect::set(&obj, &key, &val).unwrap();
}
obj.into()
}
虽然不能 100% 精确转换,但在大多数场景下够用了。
局限性 & 注意事项
再强大的工具也有短板,run 也不例外。
❌ 不适合生产部署
run 的定位是“快速实验、学习、调试”,而不是替代正式构建系统。
你不应该用它来跑线上服务,原因如下:
缺乏完整的依赖管理 没有构建缓存优化 安全性较弱(沙箱可能被绕过) 日志和监控能力有限
⚠️ 某些语言必须显式声明 --lang
比如 .m 文件可能是 Objective-C 也可能是 MATLAB,.pl 可能是 Perl 也可能是 Prolog。
所以在这些情况下,必须手动指定语言:
run --lang objc hello.m
run --lang matlab analyze.pl
否则会报错:“无法确定语言类型”。
? 小众语言支持尚不完善
虽然官方说支持 25+ 语言,但像 Haskell、Erlang、Clojure 这类函数式语言的支持还处于实验阶段。
尤其是涉及复杂依赖的项目(如 Cabal、Leiningen),目前还无法自动解析。
对比同类工具:run 到底赢在哪?
npx | |||||
deno run | |||||
scriptisto | |||||
playground | |||||
run | 25+ | 否(可选) | 极快(本地二进制) | 低 |
可以看到,run 在“本地化 + 多语言 + 交互性”三个方面做到了极致平衡。
特别是相比在线 Playground,它没有网络延迟、不依赖浏览器、能读写本地文件、支持管道操作——这才是真正的生产力工具。
教育领域的革命性应用
想象一下:
一个计算机老师上课讲“三种语言实现斐波那契数列”,以前他得分别打开三个终端,切换三个环境。
现在呢?
run
>> :lang py
>>> def fib(n): return n if n <= 1 else fib(n-1)+fib(n-2)
>>> fib(10)
55
>> :lang js
>>> const fib = n => n <= 1 ? n : fib(n-1) + fib(n-2);
>>> fib(10)
55
>> :lang rs
>>> fn fib(n: u32) -> u32 { if n <= 1 { n } else { fib(n-1) + fib(n-2) } }
>>> fib(10)
55
同一窗口,无缝切换,对比教学,直观高效。
学生回家也不用担心环境问题,只要装一个 run,就能继续练习。
这对降低编程学习门槛有着深远意义。
总结:未来已来,只是尚未普及
run 这个项目让我想起了当年 Docker 刚出现时的感觉——
“原来环境问题是可以被彻底解决的。”
它不是一个简单的命令封装工具,而是一种新的开发范式:
以开发者为中心,屏蔽底层差异,让代码即价值。
也许几年后,我们会习以为常地在一个终端里自由穿梭于 Python、Go、Rust、JS 之间,就像今天我们在 VS Code 里切换标签页一样自然。
而 run,或许就是这场变革的起点。
你可以马上动手试试的事
安装
runcargo install run-kit测试你的第一段跨语言代码
run --lang py --code "data = {'msg': 'Hello'}"
:lang js
console.log(data.msg)写个实用小脚本
比如把 Markdown 转 HTML(用 Pandoc):echo "# 标题\n这是内容" | run sh --code "pandoc -f markdown -t html | sed 's/^/<p>/; s/$/<\/p>/'"贡献一份文档或示例
项目欢迎 PR!你可以提交某个冷门语言的使用指南,或者添加新功能建议。
最后送大家一句鸡汤
“优秀的工具不会让你变得更聪明,但它会让你显得更高效。”
在这个信息爆炸的时代,谁掌握了高效的工具链,谁就掌握了时间的主动权。
而 run,正是这样一把打开效率之门的钥匙。
参考资料
https://github.com/Esubaalew/run/releases: https://github.com/Esubaalew/run/releases
本文链接:https://kinber.cn/post/5710.html 转载需授权!
推荐本站淘宝优惠价购买喜欢的宝贝:

支付宝微信扫一扫,打赏作者吧~
