Introdução
Executar processos externos permite que seu programa Zig interaja com outras ferramentas do sistema, execute comandos shell, compile código e automatize tarefas. A API std.process.Child oferece controle completo sobre a execução de processos filhos.
Nesta receita, você aprenderá a executar comandos, capturar saída e verificar o resultado.
Pré-requisitos
- Zig instalado (versão 0.13+). Veja o guia de instalação
- Conhecimento básico de Zig. Consulte a introdução ao Zig
Executar Comando Simples
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Executar 'ls -la' e capturar a saída
const result = try std.process.Child.run(.{
.allocator = allocator,
.argv = &[_][]const u8{ "ls", "-la" },
});
defer {
allocator.free(result.stdout);
allocator.free(result.stderr);
}
std.debug.print("Código de saída: {}\n", .{result.term});
std.debug.print("Saída:\n{s}\n", .{result.stdout});
if (result.stderr.len > 0) {
std.debug.print("Erros:\n{s}\n", .{result.stderr});
}
}
Executar com Argumentos Dinâmicos
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Construir argumentos dinamicamente
var args = std.ArrayList([]const u8).init(allocator);
defer args.deinit();
try args.append("echo");
try args.append("Olá");
try args.append("do");
try args.append("Zig!");
const result = try std.process.Child.run(.{
.allocator = allocator,
.argv = args.items,
});
defer {
allocator.free(result.stdout);
allocator.free(result.stderr);
}
std.debug.print("Saída: {s}", .{result.stdout});
}
Verificar Código de Retorno
const std = @import("std");
fn executarComando(allocator: std.mem.Allocator, argv: []const []const u8) !bool {
const result = try std.process.Child.run(.{
.allocator = allocator,
.argv = argv,
});
defer {
allocator.free(result.stdout);
allocator.free(result.stderr);
}
switch (result.term) {
.exited => |code| {
if (code == 0) {
std.debug.print("Comando executado com sucesso\n", .{});
return true;
} else {
std.debug.print("Comando falhou com código {d}\n", .{code});
if (result.stderr.len > 0) {
std.debug.print("Erro: {s}\n", .{result.stderr});
}
return false;
}
},
.signal => |sig| {
std.debug.print("Processo terminado por sinal {d}\n", .{sig});
return false;
},
else => {
std.debug.print("Término inesperado\n", .{});
return false;
},
}
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Comando que deve funcionar
_ = try executarComando(allocator, &[_][]const u8{ "echo", "teste" });
// Comando que pode falhar
_ = try executarComando(allocator, &[_][]const u8{ "ls", "/caminho/que/nao/existe" });
}
Executar com Diretório de Trabalho
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Executar 'pwd' em diretório específico
const result = try std.process.Child.run(.{
.allocator = allocator,
.argv = &[_][]const u8{"pwd"},
.cwd = "/tmp",
});
defer {
allocator.free(result.stdout);
allocator.free(result.stderr);
}
std.debug.print("Diretório de trabalho: {s}", .{result.stdout});
}
Capturar Saída Linha por Linha
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const result = try std.process.Child.run(.{
.allocator = allocator,
.argv = &[_][]const u8{ "ls", "-1", "/tmp" },
});
defer {
allocator.free(result.stdout);
allocator.free(result.stderr);
}
// Processar saída linha por linha
var linhas = std.mem.splitScalar(u8, result.stdout, '\n');
var count: usize = 0;
std.debug.print("Arquivos em /tmp:\n", .{});
while (linhas.next()) |linha| {
if (linha.len == 0) continue;
count += 1;
if (count <= 10) {
std.debug.print(" {d}. {s}\n", .{ count, linha });
}
}
if (count > 10) {
std.debug.print(" ... e mais {d} arquivos\n", .{count - 10});
}
std.debug.print("Total: {d} arquivos\n", .{count});
}
Dicas e Boas Práticas
Sempre libere stdout e stderr: Use
defer allocator.free()para ambos.Verifique o código de saída: Nem todo comando retorna 0 para sucesso.
Evite shell injection: Passe argumentos como array, não como string concatenada.
Limite o tamanho da saída: Use
max_output_bytespara evitar consumir memória demais.Trate sinais: Processos podem ser terminados por sinais, não apenas por exit codes.
Receitas Relacionadas
- Argumentos de Linha de Comando - Receber argumentos
- Variáveis de Ambiente - Configuração
- Informações do Sistema - Info do OS
- Time e Timestamps - Medir tempo de execução