std.process — Gerenciamento de Processos
O módulo std.process fornece funcionalidades para gerenciar processos no Zig. Isso inclui a execução de processos filhos, acesso a variáveis de ambiente, leitura de argumentos de linha de comando e controle do ciclo de vida de processos. Este módulo é essencial para construir ferramentas CLI, scripts de automação e qualquer aplicação que precise interagir com outros programas do sistema.
Visão Geral
const std = @import("std");
const process = std.process;
O std.process organiza suas funcionalidades em torno de três áreas principais: execução de processos filhos via Child, acesso ao ambiente do processo atual e manipulação de argumentos.
Funções Principais
Argumentos de Linha de Comando
// Obtém os argumentos de linha de comando
pub fn std.process.argsAlloc(allocator: Allocator) ![][:0]u8
// Libera os argumentos alocados
pub fn std.process.argsFree(allocator: Allocator, args: [][:0]u8) void
// Iterador sobre argumentos (sem alocação)
pub fn std.process.args() ArgIterator
Variáveis de Ambiente
// Obtém mapa completo de variáveis de ambiente
pub fn std.process.getEnvMap(allocator: Allocator) !EnvMap
// Variável individual (via std.posix)
pub fn std.posix.getenv(name: []const u8) ?[]const u8
Processos Filhos (Child)
// Cria e configura um processo filho
pub const Child = struct {
pub fn init(argv: []const []const u8, allocator: Allocator) Child
pub fn spawn(self: *Child) !void
pub fn wait(self: *Child) !Term
pub fn kill(self: *Child) !void
};
Exemplo 1: Leitura de Argumentos
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
// Método 1: Iterador (sem alocação de heap)
var args = std.process.args();
try stdout.writeAll("=== Argumentos (Iterador) ===\n");
var i: usize = 0;
while (args.next()) |arg| {
try stdout.print(" argv[{d}] = {s}\n", .{ i, arg });
i += 1;
}
// Método 2: Todos de uma vez (aloca no heap)
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const todos_args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, todos_args);
try stdout.print("\nTotal de argumentos: {d}\n", .{todos_args.len});
// Processa flags simples
for (todos_args[1..]) |arg| {
if (std.mem.eql(u8, arg, "--verbose") or std.mem.eql(u8, arg, "-v")) {
try stdout.writeAll("Modo verbose ativado!\n");
} else if (std.mem.startsWith(u8, arg, "--output=")) {
const valor = arg["--output=".len..];
try stdout.print("Arquivo de saída: {s}\n", .{valor});
} else if (!std.mem.startsWith(u8, arg, "-")) {
try stdout.print("Argumento posicional: {s}\n", .{arg});
}
}
}
Exemplo 2: Variáveis de Ambiente
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const stdout = std.io.getStdOut().writer();
// Acesso individual via std.posix
try stdout.writeAll("=== Variáveis Importantes ===\n");
const vars_interesse = [_][]const u8{ "HOME", "USER", "PATH", "SHELL", "LANG", "EDITOR" };
for (vars_interesse) |nome| {
if (std.posix.getenv(nome)) |valor| {
const preview = if (valor.len > 50) valor[0..50] else valor;
const sufixo: []const u8 = if (valor.len > 50) "..." else "";
try stdout.print(" {s:<8} = {s}{s}\n", .{ nome, preview, sufixo });
} else {
try stdout.print(" {s:<8} = (indefinida)\n", .{nome});
}
}
// Mapa completo de variáveis de ambiente
var env_map = try std.process.getEnvMap(allocator);
defer env_map.deinit();
try stdout.print("\nTotal de variáveis de ambiente: {d}\n", .{env_map.count()});
// Filtra variáveis que começam com prefixo específico
try stdout.writeAll("\n=== Variáveis XDG ===\n");
var iter = env_map.iterator();
var contagem_xdg: u32 = 0;
while (iter.next()) |entry| {
if (std.mem.startsWith(u8, entry.key_ptr.*, "XDG_")) {
try stdout.print(" {s} = {s}\n", .{ entry.key_ptr.*, entry.value_ptr.* });
contagem_xdg += 1;
}
}
if (contagem_xdg == 0) {
try stdout.writeAll(" (nenhuma variável XDG encontrada)\n");
}
}
Exemplo 3: Executando Processos Filhos
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const stdout = std.io.getStdOut().writer();
// Executa comando e captura saída
try stdout.writeAll("=== Executando 'uname -a' ===\n");
const resultado = try std.process.Child.run(.{
.allocator = allocator,
.argv = &.{ "uname", "-a" },
});
defer allocator.free(resultado.stdout);
defer allocator.free(resultado.stderr);
try stdout.print("Saída: {s}\n", .{resultado.stdout});
try stdout.print("Status: {}\n", .{resultado.term});
// Executa múltiplos comandos e compara
try stdout.writeAll("\n=== Informações do Sistema ===\n");
const comandos = [_]struct { nome: []const u8, args: []const []const u8 }{
.{ .nome = "Hostname", .args = &.{"hostname"} },
.{ .nome = "Whoami", .args = &.{"whoami"} },
.{ .nome = "Data", .args = &.{ "date", "+%Y-%m-%d %H:%M:%S" } },
.{ .nome = "Uptime", .args = &.{"uptime"} },
};
for (comandos) |cmd| {
const res = std.process.Child.run(.{
.allocator = allocator,
.argv = cmd.args,
}) catch |err| {
try stdout.print(" {s}: erro - {}\n", .{ cmd.nome, err });
continue;
};
defer allocator.free(res.stdout);
defer allocator.free(res.stderr);
// Remove newline final
const saida = std.mem.trimRight(u8, res.stdout, "\n");
try stdout.print(" {s}: {s}\n", .{ cmd.nome, saida });
}
}
Exemplo 4: Construtor de Processos com Pipes
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const stdout = std.io.getStdOut().writer();
// Processo com controle manual de spawn/wait
var child = std.process.Child.init(
.{ .argv = &.{ "echo", "Olá do processo filho!" } },
allocator,
);
child.stdout_behavior = .pipe;
try child.spawn();
// Lê stdout do processo filho
const child_stdout = child.stdout.?.reader();
const output = try child_stdout.readAllAlloc(allocator, 4096);
defer allocator.free(output);
const term = try child.wait();
try stdout.print("Saída do filho: {s}", .{output});
try stdout.print("Código de saída: {}\n", .{term});
// Encadeando processos (pipeline)
try stdout.writeAll("\n=== Pipeline: ls | wc -l ===\n");
const pipeline_result = try std.process.Child.run(.{
.allocator = allocator,
.argv = &.{ "sh", "-c", "ls -la /tmp | head -5" },
});
defer allocator.free(pipeline_result.stdout);
defer allocator.free(pipeline_result.stderr);
try stdout.print("{s}\n", .{pipeline_result.stdout});
}
Tratamento de Erros
O std.process usa o sistema de erros do Zig extensivamente. Os erros mais comuns incluem:
| Erro | Descrição |
|---|---|
error.FileNotFound | Comando não encontrado no PATH |
error.AccessDenied | Sem permissão para executar |
error.OutOfMemory | Memória insuficiente |
error.Unexpected | Erro de sistema inesperado |
const result = std.process.Child.run(.{
.allocator = allocator,
.argv = &.{"comando_inexistente"},
}) catch |err| switch (err) {
error.FileNotFound => {
std.debug.print("Comando não encontrado!\n", .{});
return;
},
error.AccessDenied => {
std.debug.print("Sem permissão!\n", .{});
return;
},
else => return err,
};
Módulos Relacionados
- std.os — Interface com o sistema operacional
- std.fs — Sistema de arquivos
- std.time — Tempo e timestamps
- std.debug — Depuração e stack traces
- std.log — Sistema de logging