Zig para Automacao e Scripts: Substituindo Python e Bash
Quando pensamos em automacao, Python e Bash sao as primeiras linguagens que vem a mente. Sao escolhas consagradas, mas carregam limitacoes reais: Python exige runtime e gerenciamento de dependencias, Bash fica ilegivel conforme cresce, e ambos sao ordens de magnitude mais lentos que linguagens compiladas.
Zig oferece uma alternativa interessante: binarios estaticos de poucos megabytes, sem runtime, com cross-compilation trivial e uma standard library poderosa o suficiente para cobrir a maioria dos cenarios de automacao.
Neste artigo, vamos explorar como usar Zig para tarefas de automacao e scripting, com exemplos praticos de operacoes de filesystem, argumentos CLI, requisicoes HTTP e execucao de processos.
Por que Considerar Zig para Automacao
Antes de mergulhar no codigo, vale entender onde Zig se destaca frente a Python e Bash:
- Binario unico sem dependencias: distribua uma unica executable, sem pip install, virtualenv ou interpreters
- Performance previsivel: operacoes de I/O e processamento de texto sao ordens de magnitude mais rapidas
- Cross-compilation nativa: compile para Linux, macOS e Windows a partir de qualquer plataforma com um unico comando
- Tratamento de erros explicito: sem excecoes silenciosas ou erros engolidos pelo shell — error handling robusto e parte da linguagem
- Interoperabilidade com C: chame qualquer biblioteca C diretamente, sem bindings manuais
Operacoes de File System
Uma das tarefas mais comuns em scripts e manipular arquivos. Veja como listar, filtrar e copiar arquivos em Zig:
const std = @import("std");
const fs = std.fs;
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Abrir diretorio e iterar sobre arquivos
const dir = try fs.cwd().openDir(".", .{ .iterate = true });
var iter = dir.iterate();
var log_files = std.ArrayList([]const u8).init(allocator);
defer log_files.deinit();
while (try iter.next()) |entry| {
if (entry.kind != .file) continue;
// Filtrar apenas arquivos .log
if (std.mem.endsWith(u8, entry.name, ".log")) {
const name_copy = try allocator.dupe(u8, entry.name);
try log_files.append(name_copy);
}
}
// Processar arquivos encontrados
const stdout = std.io.getStdOut().writer();
for (log_files.items) |name| {
try stdout.print("Encontrado: {s}\n", .{name});
}
// Copiar arquivo
try fs.cwd().copyFile("origem.txt", fs.cwd(), "destino.txt", .{});
}
Comparado ao equivalente em Bash (find . -name "*.log") ou Python (pathlib.Path.glob), o codigo Zig e mais verboso. Porem, voce ganha checagem de erros em cada operacao e performance muito superior em diretorios grandes.
Parsing de Argumentos CLI
Scripts uteis precisam aceitar argumentos. A standard library do Zig oferece o std.process.argsWithAllocator para isso:
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var args = try std.process.argsWithAllocator(allocator);
defer args.deinit();
// Pular o nome do programa
_ = args.skip();
var verbose = false;
var output_path: ?[]const u8 = null;
while (args.next()) |arg| {
if (std.mem.eql(u8, arg, "--verbose") or std.mem.eql(u8, arg, "-v")) {
verbose = true;
} else if (std.mem.eql(u8, arg, "--output") or std.mem.eql(u8, arg, "-o")) {
output_path = args.next() orelse {
std.debug.print("Erro: --output requer um caminho\n", .{});
std.process.exit(1);
};
}
}
if (verbose) {
std.debug.print("Modo verboso ativado\n", .{});
}
if (output_path) |path| {
std.debug.print("Saida: {s}\n", .{path});
}
}
Para projetos maiores, o ecossistema Zig tem bibliotecas como clap que oferecem parsing mais sofisticado com help automatico. Veja mais opcoes no guia de ecossistema e ferramentas.
Requisicoes HTTP e Parsing de JSON
Automacao moderna frequentemente envolve interagir com APIs. Zig tem suporte HTTP e JSON na standard library:
const std = @import("std");
pub fn fetchJson(allocator: std.mem.Allocator, url: []const u8) !std.json.Parsed(std.json.Value) {
var client = std.http.Client{ .allocator = allocator };
defer client.deinit();
// Fazer requisicao GET
var buf: [4096]u8 = undefined;
var req = try client.open(.GET, try std.Uri.parse(url), .{
.server_header_buffer = &buf,
});
defer req.deinit();
try req.send();
try req.wait();
// Ler o corpo da resposta
const body = try req.reader().readAllAlloc(allocator, 1024 * 1024);
defer allocator.free(body);
// Parsear JSON
return try std.json.parseFromSlice(std.json.Value, allocator, body, .{});
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const parsed = try fetchJson(allocator, "https://api.github.com/repos/ziglang/zig");
defer parsed.deinit();
const root = parsed.value.object;
if (root.get("stargazers_count")) |stars| {
std.debug.print("Stars: {}\n", .{stars.integer});
}
}
Enquanto em Python voce faria requests.get(url).json() em uma linha, Zig exige mais codigo — mas o resultado e um binario de 1-2 MB que roda em qualquer servidor sem instalar nada.
Execucao de Processos e Pipelines
Scripts de automacao frequentemente precisam executar outros programas. Veja como fazer isso em Zig:
const std = @import("std");
pub fn runCommand(allocator: std.mem.Allocator, argv: []const []const u8) ![]u8 {
var child = std.process.Child.init(argv, allocator);
child.stdout_behavior = .Pipe;
child.stderr_behavior = .Pipe;
try child.spawn();
const stdout = try child.stdout.?.reader().readAllAlloc(allocator, 10 * 1024 * 1024);
const result = try child.wait();
if (result.Exited != 0) {
std.debug.print("Comando falhou com codigo: {}\n", .{result.Exited});
}
return stdout;
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Pipeline: listar commits recentes
const git_log = try runCommand(allocator, &.{ "git", "log", "--oneline", "-10" });
defer allocator.free(git_log);
std.debug.print("Ultimos commits:\n{s}\n", .{git_log});
// Executar build
const build_output = try runCommand(allocator, &.{ "zig", "build", "--release=safe" });
defer allocator.free(build_output);
std.debug.print("Build concluido.\n", .{});
}
Esse padrao e a base para ferramentas de deploy, pipelines de CI e processadores de log. O build system do Zig ja usa esse conceito internamente nos build steps customizados.
Comparativo: Zig vs Python vs Bash
| Criterio | Zig | Python | Bash |
|---|---|---|---|
| Tempo de startup | < 1ms | 30-100ms | ~5ms |
| Dependencias externas | Nenhuma | pip/venv | Varia por distro |
| Tamanho do executavel | 1-5 MB | Runtime ~30 MB | Interpretado |
| Cross-compilation | Nativa, trivial | PyInstaller (fragil) | Nao portavel |
| Tratamento de erros | Explicito, compile-time | Excecoes em runtime | $? e trap |
| Processamento de texto | Manual, rapido | Excelente (regex, libs) | sed/awk (limitado) |
| Curva de aprendizado | Moderada | Baixa | Baixa (escala mal) |
| Performance em I/O | Excelente | Moderada | Boa (via coreutils) |
| Adequado para scripts < 50 linhas | Nao | Sim | Sim |
| Adequado para ferramentas de deploy | Sim | Sim | Parcialmente |
Quando Zig e a Escolha Certa
Zig brilha para automacao quando:
- O script sera distribuido: binario unico sem dependencias simplifica o deploy em servidores, containers e CI/CD
- Performance importa: processamento de logs, transformacao de dados, operacoes em massa no filesystem
- Cross-platform e necessario: compile para Linux ARM no seu Mac sem Docker ou VMs
- O script cresceu demais para Bash: se tem mais de 200 linhas de Bash, Zig provavelmente sera mais mantenivel. Outras opcoes compiladas populares para CLI incluem Go e Rust
- Precisa interagir com C: chamar bibliotecas C nativas sem FFI overhead, ideal para automacao de sistemas
Quando Zig e Demais
Nao use Zig quando:
- E um one-liner:
find . -name "*.tmp" -deletenao precisa ser compilado - Prototipagem rapida: Python ainda e imbativel para testar ideias rapidamente
- Manipulacao de texto complexa: regex, parsing de CSV, transformacao de dados tabulares — Python tem bibliotecas superiores
- Automacao de infraestrutura: Ansible, Terraform e ferramentas especializadas existem por bons motivos
Casos de Uso Reais
Desenvolvedores e empresas ja usam Zig para automacao em producao:
- Build scripts: o proprio build system do Zig e escrito em Zig, substituindo Makefiles
- Ferramentas de deploy: rclone-like tools que sincronizam arquivos via WebDAV ou S3
- Processadores de log: analisam gigabytes de logs em segundos, aproveitando SIMD para busca de padroes
- Geradores de codigo: usam comptime para gerar codigo em tempo de compilacao
- Testes automatizados: o framework de testes nativo facilita testar ferramentas CLI
Para gerenciar dependencias dos seus scripts-ferramenta, confira nosso guia de pacotes com build.zig.zon.
Perguntas Frequentes
Zig consegue substituir completamente Python para scripting?
Nao completamente. Python tem um ecossistema de bibliotecas imensamente maior para tarefas como web scraping, analise de dados e machine learning. Zig substitui bem em cenarios de performance, distribuicao e automacao de sistemas.
Preciso aprender toda a linguagem Zig para fazer scripts?
Nao. Para automacao, voce precisa dominar basicamente: I/O de arquivos, process spawning, parsing de argumentos e a standard library. Conceitos avancados como comptime e allocators customizados sao opcionais nesse contexto.
Como distribuir meus scripts Zig em servidores Linux?
Compile com zig build --release=safe e copie o binario. Sem dependencias — funciona em qualquer distribuicao Linux. Para multiplas plataformas, use a cross-compilation nativa do Zig.
Zig tem algo como o pip install para bibliotecas de automacao?
Sim, o Zig tem um sistema de pacotes via build.zig.zon. Voce declara dependencias e o zig fetch baixa e verifica automaticamente.
Scripts em Zig sao mais rapidos que Python?
Sim, significativamente. Em benchmarks de I/O e processamento de texto, Zig tipicamente e 10-100x mais rapido que Python. A diferenca e mais notavel em operacoes CPU-bound e processamento de grandes volumes de dados.