Introdução
Ler argumentos de linha de comando é fundamental para criar ferramentas CLI, scripts e programas configuráveis. Zig oferece acesso direto aos argumentos via std.process.args() e std.process.argsWithAllocator().
Nesta receita, você aprenderá a processar argumentos de diferentes formas.
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
Ler Argumentos Básicos
const std = @import("std");
pub fn main() !void {
// args() retorna um iterador sobre os argumentos
var args = std.process.args();
// O primeiro argumento é sempre o nome do programa
const programa = args.next().?;
std.debug.print("Programa: {s}\n", .{programa});
// Iterar sobre os demais argumentos
std.debug.print("Argumentos:\n", .{});
var i: usize = 1;
while (args.next()) |arg| {
std.debug.print(" [{d}] {s}\n", .{ i, arg });
i += 1;
}
if (i == 1) {
std.debug.print(" (nenhum argumento)\n", .{});
}
}
Execute com: zig run main.zig -- argumento1 argumento2 argumento3
Coletar Argumentos em Array
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Coletar todos os argumentos em um slice
const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);
std.debug.print("Total de argumentos: {d}\n", .{args.len});
for (args, 0..) |arg, i| {
std.debug.print(" args[{d}] = \"{s}\"\n", .{ i, arg });
}
}
Parsear Flags e Opções
const std = @import("std");
const Config = struct {
verbose: bool = false,
output: ?[]const u8 = null,
count: u32 = 1,
arquivos: std.ArrayList([]const u8),
pub fn init(allocator: std.mem.Allocator) Config {
return .{
.arquivos = std.ArrayList([]const u8).init(allocator),
};
}
pub fn deinit(self: *Config) void {
self.arquivos.deinit();
}
};
fn parsearArgs(allocator: std.mem.Allocator) !Config {
var config = Config.init(allocator);
errdefer config.deinit();
var args = std.process.args();
_ = args.next(); // Pular nome do programa
while (args.next()) |arg| {
if (std.mem.eql(u8, arg, "-v") or std.mem.eql(u8, arg, "--verbose")) {
config.verbose = true;
} else if (std.mem.eql(u8, arg, "-o") or std.mem.eql(u8, arg, "--output")) {
config.output = args.next() orelse {
std.debug.print("Erro: -o requer um valor\n", .{});
return error.InvalidArgument;
};
} else if (std.mem.eql(u8, arg, "-n") or std.mem.eql(u8, arg, "--count")) {
const val_str = args.next() orelse {
std.debug.print("Erro: -n requer um número\n", .{});
return error.InvalidArgument;
};
config.count = std.fmt.parseInt(u32, val_str, 10) catch {
std.debug.print("Erro: '{s}' não é um número válido\n", .{val_str});
return error.InvalidArgument;
};
} else if (std.mem.startsWith(u8, arg, "-")) {
std.debug.print("Opção desconhecida: {s}\n", .{arg});
return error.InvalidArgument;
} else {
try config.arquivos.append(arg);
}
}
return config;
}
fn mostrarUso() void {
std.debug.print(
\\Uso: programa [opções] [arquivos...]
\\
\\Opções:
\\ -v, --verbose Modo verboso
\\ -o, --output Arquivo de saída
\\ -n, --count Número de repetições
\\
\\
, .{});
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var config = parsearArgs(allocator) catch {
mostrarUso();
return;
};
defer config.deinit();
std.debug.print("Configuração:\n", .{});
std.debug.print(" Verbose: {}\n", .{config.verbose});
std.debug.print(" Output: {s}\n", .{config.output orelse "(padrão)"});
std.debug.print(" Count: {d}\n", .{config.count});
std.debug.print(" Arquivos: {d}\n", .{config.arquivos.items.len});
for (config.arquivos.items) |arq| {
std.debug.print(" - {s}\n", .{arq});
}
}
Subcomandos Estilo Git
const std = @import("std");
fn cmdInit() void {
std.debug.print("Inicializando projeto...\n", .{});
}
fn cmdBuild(args: *std.process.ArgIterator) void {
var release = false;
while (args.next()) |arg| {
if (std.mem.eql(u8, arg, "--release")) {
release = true;
}
}
std.debug.print("Compilando em modo {s}...\n", .{if (release) "release" else "debug"});
}
fn cmdHelp() void {
std.debug.print(
\\Comandos disponíveis:
\\ init Inicializar projeto
\\ build Compilar projeto [--release]
\\ help Mostrar esta ajuda
\\
, .{});
}
pub fn main() !void {
var args = std.process.args();
_ = args.next(); // nome do programa
const subcomando = args.next() orelse {
std.debug.print("Erro: nenhum comando fornecido\n\n", .{});
cmdHelp();
return;
};
if (std.mem.eql(u8, subcomando, "init")) {
cmdInit();
} else if (std.mem.eql(u8, subcomando, "build")) {
cmdBuild(&args);
} else if (std.mem.eql(u8, subcomando, "help")) {
cmdHelp();
} else {
std.debug.print("Comando desconhecido: {s}\n\n", .{subcomando});
cmdHelp();
}
}
Dicas e Boas Práticas
O primeiro argumento é o programa: Sempre pule
args[0]ao processar argumentos do usuário.Valide sempre: Verifique se flags com valor realmente receberam o valor esperado.
Mostre uso em caso de erro: Sempre ofereça uma mensagem de ajuda clara.
Suporte formas curtas e longas:
-ve--verbosepara melhor usabilidade.
Receitas Relacionadas
- Variáveis de Ambiente - Ler variáveis do sistema
- Executar Processos Externos - Rodar comandos
- Formatar Strings com std.fmt - Formatação de saída
- Ler Conteúdo de Arquivo - Processar arquivos de entrada