🌗 ← Índice
Data: 14/08/2026
Nível: Intermediário-Avançado (Mês 3 — Projetos Reais)
Todo CLI profissional tem: --help, argumentos, flags, validação e mensagens de erro claras. O argparse (biblioteca padrão) entrega tudo isso de graça:
python ferramenta.py --help
# usage: ferramenta.py [-h] [--verbose] arquivo
import argparse
parser = argparse.ArgumentParser(
description="Conta palavras de um arquivo de texto",
)
parser.add_argument("arquivo", help="Caminho do arquivo") # posicional
parser.add_argument("--verbose", action="store_true", help="Mostra detalhes") # flag
parser.add_argument("-o", "--output", default=None, help="Arquivo de saída")
args = parser.parse_args()
print(f"Arquivo: {args.arquivo}")
print(f"Verbose: {args.verbose}")
python contador.py notas.txt --verbose -o resumo.txt
# Arquivo: notas.txt
# Verbose: True
parser.add_argument("--vezes", type=int, default=1) # inteiro
parser.add_argument("--taxa", type=float, default=0.1) # float
parser.add_argument("--itens", nargs="+", default=[]) # lista (1+ itens)
parser.add_argument("--opcao", choices=["rapido", "lento"]) # valores válidos
parser.add_argument("--obrigatorio", required=True) # obrigatório
parser.add_argument("--porta", type=int, default=80)
# Validação manual após o parse
if not (1 <= args.porta <= 65535):
parser.error("A porta deve estar entre 1 e 65535")
import argparse
from pathlib import Path
def contar_palavras(texto: str) -> int:
return len(texto.split())
def main():
parser = argparse.ArgumentParser(description="Conta palavras de um arquivo")
parser.add_argument("arquivo", type=Path, help="Caminho do arquivo")
parser.add_argument("--saida", "-s", help="Salvar resultado em arquivo")
parser.add_argument("--verbose", "-v", action="store_true")
args = parser.parse_args()
if not args.arquivo.exists():
parser.error(f"Arquivo não encontrado: {args.arquivo}")
texto = args.arquivo.read_text(encoding="utf-8")
total = contar_palavras(texto)
if args.verbose:
print(f"Arquivo: {args.arquivo} ({len(texto)} caracteres)")
print(f"Palavras: {total}")
if args.saida:
Path(args.saida).write_text(f"{total}\n", encoding="utf-8")
if args.verbose:
print(f"Resultado salvo em {args.saida}")
if __name__ == "__main__":
main()
import argparse
parser = argparse.ArgumentParser(description="Ferramenta de backup")
subparsers = parser.add_subparsers(dest="comando", required=True)
# subcomando: backup
parser_backup = subparsers.add_parser("backup", help="Cria um backup")
parser_backup.add_argument("origem", help="Pasta de origem")
parser_backup.add_argument("--destino", default="/tmp/backup")
# subcomando: restaurar
parser_restaurar = subparsers.add_parser("restaurar", help="Restaura um backup")
parser_restaurar.add_argument("arquivo", help="Arquivo .zip")
args = parser.parse_args()
if args.comando == "backup":
print(f"Backup de {args.origem} → {args.destino}")
elif args.comando == "restaurar":
print(f"Restaurando {args.arquivo}")
python backup.py backup /etc/nginx
python backup.py restaurar /tmp/backup.zip
python backup.py --help # lista os subcomandos
Crie um CLI organizar_cli.py que envolve o organizador da Aula P19:
python organizar_cli.py /tmp/teste_downloads # organiza a pasta
python organizar_cli.py /tmp/teste_downloads --tipo pdf # só PDFs
python organizar_cli.py /tmp/teste_downloads --resumo # imprime resumo
python organizar_cli.py /tmp/teste_downloads --seco # simula (não move)
Requisitos: --tipo (filtra por extensão), --resumo (flag), --seco (dry-run, não move nada, só mostra o que faria).
import argparse
from pathlib import Path
TIPOS = {
"Imagens": {".jpg", ".png", ".gif"},
"Documentos": {".pdf", ".docx", ".txt", ".md"},
"Planilhas": {".xlsx", ".csv"},
}
def main():
parser = argparse.ArgumentParser(description="Organiza arquivos por tipo")
parser.add_argument("pasta", type=Path, help="Pasta a organizar")
parser.add_argument("--tipo", default=None, help="Extensão a filtrar (ex: pdf)")
parser.add_argument("--resumo", action="store_true", help="Imprime resumo")
parser.add_argument("--seco", action="store_true", help="Modo simulação (não move)")
args = parser.parse_args()
if not args.pasta.is_dir():
parser.error(f"Pasta não encontrada: {args.pasta}")
movidos = 0
for arquivo in args.pasta.iterdir():
if arquivo.is_dir():
continue
if args.tipo and arquivo.suffix.lower() != f".{args.tipo.lower()}":
continue
categoria = "Outros"
for nome, ext in TIPOS.items():
if arquivo.suffix.lower() in ext:
categoria = nome
break
destino = args.pasta / categoria
if args.seco:
print(f"[simulado] {arquivo.name} → {categoria}/")
else:
destino.mkdir(exist_ok=True)
arquivo.rename(destino / arquivo.name)
print(f"Movido: {arquivo.name} → {categoria}/")
movidos += 1
if args.resumo or args.seco:
print(f"\nTotal: {movidos} arquivo(s)")
if __name__ == "__main__":
main()
💡 O --seco (dry-run) é a prática mais valiosa: permite testar com segurança antes de mover arquivos reais.
HB Estudos · ← Voltar ao índice de Python