1. 引言:为什么选择Elixir?
"用Erlang虚拟机跑命令行工具?这听起来像用航空母舰钓鱼啊!"——这是很多人初次接触Elixir时的疑惑。但当你真正了解Elixir的并发模型、模式匹配和宏系统后,就会发现它其实是构建命令行工具的绝佳选择。举个例子,GitHub的Semantic代码分析工具就是用Elixir开发的,每天处理数百万次代码解析请求。
2. 环境准备
(技术栈:Elixir 1.14+)
# 安装最新Elixir(以macOS为例)
brew update
brew install elixir
# 验证安装
elixir -v
# 输出示例:Erlang/OTP 25 [erts-13.0.4] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit:ns]
# Elixir 1.14.3 (compiled with Erlang/OTP 25)
3. 构建第一个CLI应用
3.1 创建Mix项目
mix new magic_cli --sup
cd magic_cli
3.2 基础命令实现
# lib/magic_cli.ex
defmodule MagicCLI do
@moduledoc """
魔法命令行入口模块
"""
def main(args) do
args
|> parse_args
|> process
end
defp parse_args(args) do
{opts, _} = OptionParser.parse!(args,
strict: [help: :boolean, version: :boolean],
aliases: [h: :help, v: :version]
)
opts
end
defp process([help: true]), do: show_help()
defp process([version: true]), do: show_version()
defp process(_), do: execute_default()
defp show_help do
IO.puts """
使用说明:
--help 显示帮助信息
--version 显示版本信息
"""
end
defp show_version do
IO.puts "魔法命令行 v1.0.0"
end
defp execute_default do
IO.puts "正在施展默认魔法..."
# 这里可以添加业务逻辑
end
end
4. 进阶功能实现
4.1 子命令系统
# 修改lib/magic_cli.ex
defmodule MagicCLI do
# ...原有代码...
defp parse_args(args) do
{opts, args} = OptionParser.parse!(args,
strict: [help: :boolean, version: :boolean],
aliases: [h: :help, v: :version],
switches: [command: :string]
)
{opts, args}
end
defp process({[command: "encrypt"], file_args}) do
# 加密处理逻辑
file_args |> Enum.each(&encrypt_file/1)
end
defp process({[command: "decrypt"], file_args}) do
# 解密处理逻辑
file_args |> Enum.each(&decrypt_file/1)
end
defp encrypt_file(file) do
IO.puts "正在加密 #{file}..."
# 实际加密实现
end
defp decrypt_file(file) do
IO.puts "正在解密 #{file}..."
# 实际解密实现
end
end
4.2 彩色输出
# 添加依赖到mix.exs
defp deps do
[
{:io_ansi_table, "~> 0.1.0"}
]
end
# 使用示例
defmodule MagicCLI.Formatter do
import IO.ANSI
def success(msg) do
IO.puts [green(), "✓ ", reset(), msg]
end
def error(msg) do
IO.puts [red(), "✗ ", reset(), msg]
end
def progress_bar(current, total) do
width = 40
percent = current / total * 100
filled = round(width * current / total)
bar = [
blue_background(),
String.duplicate(" ", filled),
reset(),
String.duplicate(" ", width - filled),
" #{round(percent)}%"
]
IO.write(["\r", bar])
end
end
5. 跨平台打包
5.1 使用escript
# 修改mix.exs
def project do
[
app: :magic_cli,
escript: [main_module: MagicCLI],
version: "1.0.0",
# ...其他配置...
]
end
# 打包命令
mix escript.build
5.2 Burrito打包工具(跨平台利器)
# 添加依赖
{:burrito, github: "burrito-elixir/burrito"}
# 创建rel/envs.exs
import Config
config :magic_cli,
burrito: [
targets: [
macos: [os: :darwin, cpu: :x86_64],
linux: [os: :linux, cpu: :x86_64],
windows: [os: :windows, cpu: :x86_64]
]
]
# 打包命令
MIX_ENV=prod mix release
6. 关联技术深入
6.1 进程监控系统
defmodule MagicCLI.Watcher do
use GenServer
def start_link(_) do
GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
def init(_) do
Process.flag(:trap_exit, true)
{:ok, %{}}
end
def handle_info({:EXIT, pid, reason}, state) do
IO.puts "进程 #{inspect pid} 异常退出,原因:#{reason}"
{:noreply, state}
end
end
6.2 热更新实现
defmodule MagicCLI.LiveUpdate do
def reload do
# 重新加载所有模块
Mix.Task.run("compile")
# 清除旧版本代码
:code.purge(MagicCLI)
:code.delete(MagicCLI)
# 加载新代码
{:module, _} = Code.ensure_compiled(MagicCLI)
end
end
7. 应用场景分析
- DevOps工具链:利用Elixir的并发特性处理CI/CD流水线
- 数据处理工具:快速处理GB级日志文件
- IoT设备管理:结合Nerves框架实现嵌入式CLI
- 区块链节点工具:高效处理区块链交易数据
8. 技术优缺点对比
优势:
- 毫秒级热更新(无需重启进程)
- 天然的容错机制(Supervisor树)
- 卓越的并发处理能力(OTP加持)
- 模式匹配简化参数解析
劣势:
- 冷启动时间较长(VM启动耗时)
- 二进制体积较大(相比Go/Rust)
- 生态相对年轻(部分库不够成熟)
9. 注意事项
- 参数安全处理:使用OptionParser的strict模式
OptionParser.parse(args, strict: [valid_flag: :boolean])
- 跨平台路径处理:
Path.join(["parent", "child.txt"]) # 自动适应系统分隔符
- 版本兼容性:明确指定Erlang/OTP版本
- 内存管理:避免在长期运行的CLI中积累状态
10. 总结与展望
通过本教程,我们完成了从基础CLI到支持热更新、跨平台打包的全功能命令行工具开发。Elixir的并发模型让我们的工具可以轻松处理后台任务,而模式匹配则让复杂的参数解析变得优雅简洁。未来可以考虑集成WebAssembly运行时,或者结合Phoenix框架开发可视化CLI界面。