Python os e sys

Um programa não vive sozinho: ele roda dentro de um sistema operacional (o Ubuntu da Ana), numa pasta, com um usuário, e foi chamado por alguém, de algum jeito. Dois módulos da biblioteca padrão deixam o seu programa olhar em volta. O os (de operating system, "sistema operacional") conversa com o sistema: pastas, arquivos, variáveis de ambiente. O sys (de system, "sistema") conversa com o próprio Python: os argumentos que chegaram, a versão, onde ele procura os módulos e como encerrar o programa.

Você vai aprender
  • Com o os: a pasta atual (os.getcwd, os.chdir), o conteúdo de uma pasta (os.listdir), criar pastas (os.mkdir), testar se algo existe (os.path.exists).
  • As variáveis de ambiente com os.environ, e por que .get() é mais seguro que […].
  • Com o sys: sys.argv, sys.exit e o código de saída, sys.path, sys.version e sys.version_info.
  • Os erros reais: FileNotFoundError, FileExistsError, KeyError e o arquivo seu que "esconde" um módulo do Python.

A ideia: olhar pela janela e olhar no espelho

Quando a Ana chega para trabalhar na padaria, ela faz duas coisas sem pensar. Olha em volta: em qual sala está, o que tem nas prateleiras, se tem algum bilhete na porta. E olha para si mesma: qual é a tarefa do dia, quem pediu, a que horas pode ir embora.

MóduloOlha para…Exemplos de pergunta
osO sistema, em volta do programa (a janela)Em qual pasta estou? O que tem nela? Quem é o usuário?
sysO Python que está rodando o programa (o espelho)Com quais argumentos fui chamado? Qual é a minha versão? Como eu termino avisando que deu erro?

Os dois vêm com o Python; basta o import. Esta aula mostra as partes que um iniciante usa de verdade. Para trabalhar com caminhos de arquivos e pastas, o Python moderno tem um módulo próprio, mais confortável, que ganhou aula só para ele: Pastas e Caminhos (pathlib).

No terminal e no editor, respostas diferentes

As respostas do os e do sys dependem de onde o programa roda. As janelas de terminal desta aula mostram o computador da Ana (usuária ana, pasta /home/ana, Ubuntu). O editor do guia imita a pasta da Ana (/home/ana), mas é o Python do navegador: lá, o sys.platform é 'emscripten' (e não 'linux'), a versão (3.14.2) e as pastas do sys.path são outras (o sys.executable, não: o editor mostra /usr/bin/python3, como no Ubuntu), e faltam variáveis de ambiente como a EDITOR. As missões desta aula não dependem disso.


1. Em qual pasta estou? os.getcwd() e os.listdir()

Todo programa roda "dentro" de uma pasta, a pasta atual (em inglês, current working directory). É a mesma ideia do pwd do terminal. Quando o programa abre "estoque.csv" sem dizer a pasta, é nela que o Python procura. A Ana tem a pasta da lojinha, com alguns arquivos e uma subpasta fotos, vazia:

import os

print("Estou em:", os.getcwd())
print("Aqui tem:", os.listdir())
print("Em fotos:", os.listdir("fotos"))
$ python3 pasta.py
Estou em: /home/ana/loja
Aqui tem: ['clientes.json', 'vendas.py', 'pasta.py', 'estoque.csv', 'fotos']
Em fotos: []
os.getcwd()
"Pegue a pasta atual" (get current working directory). Devolve o caminho completo, como texto.
os.listdir()
"Liste a pasta": uma lista com os nomes do que tem dentro, arquivos e pastas misturados. Sem argumento, lista a pasta atual.
os.listdir("fotos")
Com um nome, lista aquela pasta. [] é a lista vazia: a pasta existe, mas não tem nada.

Repare na ordem: não é alfabética. O os.listdir devolve os nomes na ordem em que o sistema guardou, que pode mudar de um computador para outro. Quando a ordem importa, use sorted(os.listdir()) (aula Ordenando Listas).

A pasta atual é de onde você chamou, não de onde está o arquivo

Agora a Ana roda o mesmo programa, mas a partir da pasta de cima:

$ cd ..
$ python3 loja/pasta.py
Estou em: /home/ana
Aqui tem: ['.bash_history', 'Modelos', '.bash_logout', 'Imagens', '.config', 'Documentos', '.bashrc', 'Público', 'Downloads', 'loja', 'Área de trabalho', 'Vídeos', '.profile', 'Música']
Traceback (most recent call last):
  File "/home/ana/loja/pasta.py", line 5, in <module>
    print("Em fotos:", os.listdir("fotos"))
                       ~~~~~~~~~~^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: 'fotos'

A pasta atual agora é /home/ana, porque foi lá que a Ana estava ao chamar o programa. Por isso o listdir() mostrou a pasta pessoal dela (com os arquivos escondidos, que começam com ponto), e o "fotos" não foi encontrado: não existe /home/ana/fotos. Guarde esta regra, que pega muita gente: nomes sem pasta são procurados a partir da pasta atual, e a pasta atual depende de onde o programa foi chamado.

Missão: a pasta deste programa tem quatro arquivos (veja as abas). Mostre só os .csv, em ordem alfabética, no formato CSV: estoque.csv, vendas.csv. Dica: nome.endswith(".csv") (aula Métodos de Texto).

import os

nomes = sorted(os.listdir())
print(nomes)
produto,quantidade
bolo de cenoura,3
produto,estoque
farinha,12
Fechado no feriado.
import os

nomes = sorted(os.listdir())
planilhas = []
for nome in nomes:
    if nome.endswith(".csv"):
        planilhas.append(nome)
print("CSV:", ", ".join(planilhas))

2. Criar pastas e mudar de pasta: os.mkdir, os.path.exists, os.chdir

import os

print(os.path.exists("relatorios"))
os.mkdir("relatorios")
print(os.path.exists("relatorios"))
os.chdir("relatorios")
print("Agora em:", os.getcwd())
print(os.name, repr(os.sep))
$ python3 mexe.py
False
True
Agora em: /home/ana/loja/relatorios
posix '/'
$ pwd
/home/ana/loja
os.path.exists("relatorios")
"O caminho existe?": True ou False. Antes, não existia; depois do mkdir, sim.
os.mkdir("relatorios")
Cria a pasta (de make directory, como o mkdir do terminal).
os.chdir("relatorios")
Muda a pasta atual do programa (change directory, como o cd).
os.name
O "tipo" de sistema: 'posix' no Linux e no macOS, 'nt' no Windows.
os.sep
O separador de pastas: '/' aqui; '\\' no Windows.

Repare no pwd depois: o terminal continuou em ~/loja. O os.chdir mudou a pasta só do programa, enquanto ele rodava; um programa não consegue mudar a pasta do terminal que o chamou. (É o mesmo motivo de o activate do ambiente virtual precisar do source, na aula venv.)

E se rodar o mesmo programa de novo? A pasta já existe:

$ python3 mexe.py
True
Traceback (most recent call last):
  File "/home/ana/loja/mexe.py", line 4, in <module>
    os.mkdir("relatorios")
    ~~~~~~~~^^^^^^^^^^^^^^
FileExistsError: [Errno 17] File exists: 'relatorios'

FileExistsError: "o arquivo já existe" (para o sistema, pasta também é um tipo de arquivo). O os.mkdir não cria por cima. Para "crie se ainda não existir", use os.makedirs("relatorios", exist_ok=True), que também cria as pastas do meio ("relatorios/2026/outubro") de uma vez.


3. Variáveis de ambiente: os.environ

Todo programa recebe do sistema um conjunto de variáveis de ambiente: pares nome → valor que dizem coisas sobre o lugar onde ele está rodando. Quem é o usuário, qual é a pasta pessoal, qual é o idioma. No Python, elas ficam em os.environ, que funciona como um dicionário (aula Dicionários):

import os

print("HOME:", os.environ["HOME"])
print("USER:", os.environ["USER"])
print("LANG:", os.environ["LANG"])
print("EDITOR:", os.environ.get("EDITOR"))
print("LOJA_MODO:", os.environ.get("LOJA_MODO", "normal"))
$ python3 ambiente.py
HOME: /home/ana
USER: ana
LANG: pt_BR.UTF-8
EDITOR: nano
LOJA_MODO: normal
VariávelO que guarda
HOMEA pasta pessoal do usuário
USERO nome do usuário
LANGIdioma e codificação: português do Brasil, UTF-8
EDITORO editor de texto preferido (o nano, aqui)
PATHAs pastas onde o terminal procura os programas (a que o activate muda)
os.environ["HOME"]
Pega o valor pelo nome, com colchetes. Se a variável não existir, dá erro.
os.environ.get("EDITOR")
O .get dos dicionários: devolve o valor, ou None se não existir. Sem erro.
os.environ.get("LOJA_MODO", "normal")
Com um segundo argumento: o valor padrão, quando a variável não existe. A LOJA_MODO não existe, então veio normal.

Mandando uma variável para o programa

No terminal, dá para criar uma variável só para um comando, escrevendo NOME=valor antes dele:

$ LOJA_MODO=teste python3 ambiente.py
HOME: /home/ana
USER: ana
LANG: pt_BR.UTF-8
EDITOR: nano
LOJA_MODO: teste

É um jeito muito usado de configurar um programa sem mudar o código: modo de teste, endereço de um servidor, uma senha que não pode ficar escrita no arquivo. O programa lê com os.environ.get, e quem chama decide o valor.

Missão: o programa quebra com KeyError, porque a variável LOJA_MODO não existe aqui. Troque os colchetes por .get, com "normal" como valor padrão, para mostrar Modo: normal.

import os

modo = os.environ["LOJA_MODO"]
print("Modo:", modo)
import os

modo = os.environ.get("LOJA_MODO", "normal")
print("Modo:", modo)

4. sys.argv: com o que o programa foi chamado

Você já conheceu o sys.argv na aula argparse: é a lista com o nome do programa e os argumentos que vieram depois dele, todos como texto.

$ python3 -c "import sys; print(sys.argv)" a b
['-c', 'a', 'b']

Com python3 -c, não há arquivo, e o item 0 vira '-c'; com um arquivo, é o nome dele ('ola.py'). Para programas com mais de um ou dois argumentos, prefira o argparse.


5. sys.exit: terminar o programa (e avisar como foi)

Todo programa, ao terminar, devolve ao sistema um número: o código de saída. 0 quer dizer "deu tudo certo"; qualquer outro número quer dizer "deu algum problema". No terminal, echo $? mostra o código do último comando. Quem decide o número é o sys.exit:

import sys

if len(sys.argv) < 2:
    print("Uso: python3 saida.py PRODUTO", file=sys.stderr)
    sys.exit(1)

print("Procurando", sys.argv[1])
sys.exit(0)
$ python3 saida.py bolo
Procurando bolo
$ echo $?
0
$ python3 saida.py
Uso: python3 saida.py PRODUTO
$ echo $?
1
sys.exit(1)
Termina o programa ali mesmo, com o código 1. As linhas de baixo não rodam.
sys.exit(0)
Termina com "deu certo". No fim do arquivo é opcional: um programa que chega ao fim sem erro já sai com 0.
file=sys.stderr
Manda o print para a saída de erros (standard error), um segundo canal de saída, separado do normal (sys.stdout). Na tela, os dois aparecem juntos.

Para que dois canais? Para quem chama poder separar. Com 2>/dev/null, o terminal joga fora a saída de erros, e a mensagem de uso some; mas o código 1 continua lá, avisando que algo deu errado:

$ python3 saida.py 2>/dev/null
$ echo $?
1

Esse número é o que scripts e outros programas olham para saber se o seu programa funcionou (a aula subprocess mostra o Python fazendo isso).

Formas de chamar o sys.exit

Com um texto em vez de número, o Python mostra o texto na saída de erros e sai com o código 1. É o jeito mais curto de "parar com uma mensagem":

import sys

sys.exit("Erro: o arquivo de estoque não foi encontrado.")
$ python3 saida2.py
Erro: o arquivo de estoque não foi encontrado.
$ echo $?
1
ChamadaCódigo de saídaQuando usar
(chegar ao fim do programa)0O normal: deu certo
sys.exit() ou sys.exit(0)0Terminar antes do fim, com sucesso
sys.exit(1), sys.exit(2)…O número dadoTerminar com erro; cada número pode indicar um tipo de problema (o argparse usa 2 para "chamou errado")
sys.exit("mensagem")1Terminar com erro e uma mensagem para a pessoa
(uma exceção não tratada)1O Python mostra o traceback e sai com 1

Por dentro: o SystemExit

O sys.exit não "desliga" o Python na hora: ele lança uma exceção, a SystemExit. Se ninguém a pegar, o programa termina. Por isso um try consegue segurá-la:

import sys

try:
    sys.exit(3)
except SystemExit as e:
    print("Pegou o SystemExit, código", e.code)
print("O programa continuou.")
$ python3 saida3.py
Pegou o SystemExit, código 3
O programa continuou.
$ echo $?
0

Na prática, você quase nunca faz isso de propósito. O cuidado é o contrário: um except: sem nome, que pega tudo, também engole o sys.exit. Escreva sempre o nome da exceção no except (aula try e except).

Missão: nesta caixa o programa é chamado sem argumentos e quebra com IndexError (código 1). Antes de usar o sys.argv[1], confira: se não veio argumento, mostre Uso: python3 main.py PRODUTO e termine com o código 2.

import sys

produto = sys.argv[1]
print("Procurando", produto)
import sys

if len(sys.argv) < 2:
    print("Uso: python3 main.py PRODUTO", file=sys.stderr)
    sys.exit(2)

produto = sys.argv[1]
print("Procurando", produto)

6. sys.path: onde o Python procura os módulos

Quando você escreve import random, como o Python sabe onde está o random? Ele procura numa lista de pastas, em ordem, e usa o primeiro que encontrar. A lista é o sys.path:

import sys

for pasta in sys.path:
    print(repr(pasta))
$ python3 caminhos.py
'/home/ana/loja'
'/usr/lib/python314.zip'
'/usr/lib/python3.14'
'/usr/lib/python3.14/lib-dynload'
'/usr/local/lib/python3.14/dist-packages'
'/usr/lib/python3/dist-packages'
'/home/ana/loja'
A primeira pasta é a do programa. É por isso que um módulo seu, no mesmo lugar, é encontrado (aula Criando seu Módulo).
'/usr/lib/python3.14'
A biblioteca padrão: random.py, json, os.py…
'…/python314.zip', 'lib-dynload'
Outros lugares da biblioteca padrão (o zip nem existe; o Python só procura nele se existir).
'…/dist-packages'
Os pacotes instalados pelo Ubuntu (apt). Num ambiente virtual, aparece aqui o site-packages da .venv (aula venv).

O repr() mostra cada texto com as aspas, para que um item vazio ('') também apareça. A pasta do programa vir primeiro é cômodo, mas tem uma armadilha, que está em Quando dá errado.


7. sys.version e sys.version_info: qual Python está rodando

import sys

print(sys.version)
print(sys.version_info)
print(sys.version_info.major, sys.version_info.minor)
print(sys.platform)
print(sys.executable)
if sys.version_info < (3, 12):
    print("Este programa precisa do Python 3.12 ou mais novo.")
else:
    print("Versão boa.")
$ python3 versao.py
3.14.4 (main, Aug 20 2026, 10:41:58) [GCC 15.2.0]
sys.version_info(major=3, minor=14, micro=4, releaselevel='final', serial=0)
3 14
linux
/usr/bin/python3
Versão boa.
sys.version
Um texto para pessoas lerem: a versão (3.14.4), a data em que esse Python foi compilado e o compilador usado (GCC).
sys.version_info
A mesma versão, em partes, para programas usarem: major (3), minor (14), micro (4) e o estágio ('final' é a versão lançada, não um teste).
sys.version_info < (3, 12)
Compara com uma tupla (aula Tuplas), parte por parte: 3 com 3, depois 14 com 12. É o jeito certo de conferir a versão.
sys.platform
O sistema: 'linux', 'win32' no Windows, 'darwin' no macOS.
sys.executable
O caminho do Python que está rodando (você usou na aula venv).
Não compare versões como texto

sys.version >= "3.9" parece funcionar, mas compara letra por letra: "3.14" é "menor" que "3.9", porque o caractere 1 vem antes do 9. Compare sempre o sys.version_info com uma tupla de números.


Formas diferentes de fazer a mesma coisa

TarefaCom osOutra formaQual usar
Pasta atualos.getcwd()Path.cwd() (pathlib)As duas servem; com pathlib, o resultado já vem pronto para montar caminhos
Listar uma pastaos.listdir("fotos")Path("fotos").iterdir()os.listdir para só os nomes; pathlib quando você vai abrir os arquivos
Existe?os.path.exists("x")Path("x").exists()Em código novo, pathlib
Criar pastaos.makedirs("a/b", exist_ok=True)Path("a/b").mkdir(parents=True, exist_ok=True)Tanto faz; evite o os.mkdir sozinho quando a pasta pode já existir
Variável de ambienteos.environ.get("X", "padrão")os.environ["X"].get, a não ser que o programa não possa rodar sem ela
Parar com erro—sys.exit("mensagem") ou raisesys.exit para encerrar o programa; raise dentro de funções (aula raise)

Quando dá errado

FileNotFoundError: a pasta não existe (ou o programa está em outra pasta)
import os

print(os.listdir("fotografias"))
$ python3 listar.py
Traceback (most recent call last):
  File "/home/ana/loja/listar.py", line 3, in <module>
    print(os.listdir("fotografias"))
          ~~~~~~~~~~^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: 'fotografias'
File "/home/ana/loja/listar.py", line 3
O erro foi na linha 3.
~~~~~~~~~~^^^^^^^^^^^^^^^
As marcas apontam a chamada os.listdir("fotografias").
FileNotFoundError
"Arquivo não encontrado".
[Errno 2] No such file or directory: 'fotografias'
"Erro número 2 do sistema: não existe arquivo ou pasta com esse nome". O Errno é o código que o próprio Linux deu (no editor do guia, que não é Linux, sai [Errno 44]).

A pasta se chama fotos. E lembre do caso da seção 1: o nome pode estar certo e o programa ter sido chamado de outra pasta. Como consertar: confira o nome e confira o os.getcwd().

FileExistsError: criar uma pasta que já existe

Você viu na seção 2: os.mkdir("relatorios") na segunda vez dá FileExistsError: [Errno 17] File exists: 'relatorios'. Como consertar: os.makedirs("relatorios", exist_ok=True), ou teste antes com os.path.exists.

KeyError: a variável de ambiente não existe
import os

print(os.environ["LOJA_SENHA"])
$ python3 chave.py
Traceback (most recent call last):
  File "/home/ana/loja/chave.py", line 3, in <module>
    print(os.environ["LOJA_SENHA"])
          ~~~~~~~~~~^^^^^^^^^^^^^^
  File "<frozen os>", line 709, in __getitem__
KeyError: 'LOJA_SENHA'

O traceback tem duas partes: a linha 3 do seu programa e uma linha File "<frozen os>", que é o código do próprio módulo os ("frozen", "congelado", porque ele vem embutido no Python). O erro aconteceu lá dentro, mas a causa está na sua linha. KeyError: 'LOJA_SENHA' é o mesmo erro de um dicionário sem aquela chave. Como consertar: os.environ.get("LOJA_SENHA"), ou rode com a variável: LOJA_SENHA=... python3 chave.py. Se o programa não tem como funcionar sem ela, uma mensagem clara é melhor que o traceback: sys.exit("Defina a variável LOJA_SENHA.").

Um arquivo seu com o nome de um módulo do Python

A Ana fez um teste numa pasta sorteio e chamou o arquivo de random.py. Depois escreveu o programa do sorteio:

import random

print(random.randint(1, 10))
$ python3 sortear.py
Este é o random.py da Ana, não o do Python!
Traceback (most recent call last):
  File "/home/ana/sorteio/sortear.py", line 3, in <module>
    print(random.randint(1, 10))
          ^^^^^^^^^^^^^^
AttributeError: module 'random' has no attribute 'randint' (consider renaming '/home/ana/sorteio/random.py' since it has the same name as the standard library module named 'random' and prevents importing that standard library module)

Lembra da ordem do sys.path? A pasta do programa vem primeiro. O import random achou o random.py da Ana antes do random do Python, rodou o print dele e, claro, ali não existe randint. AttributeError: module 'random' has no attribute 'randint' é "o módulo random não tem o atributo randint". E o Python ainda dá a dica entre parênteses: "considere renomear /home/ana/sorteio/random.py, porque ele tem o mesmo nome do módulo random da biblioteca padrão e impede que ele seja importado". Como consertar: renomeie o arquivo (meu_sorteio.py). Nunca dê aos seus arquivos nomes de módulos do Python: random.py, math.py, os.py, json.py, csv.py…

A dica é nova

A frase "consider renaming…" apareceu no Python 3.13. Num Python mais antigo, o erro vem só como AttributeError: module 'random' has no attribute 'randint', e você precisa lembrar sozinho dessa armadilha.


Referência rápida

CódigoO que faz
os.getcwd()A pasta atual, como texto
os.chdir("pasta")Muda a pasta atual do programa
os.listdir() / os.listdir("pasta")Lista os nomes (em ordem qualquer; use sorted)
os.mkdir("pasta")Cria uma pasta (erro se já existir)
os.makedirs("a/b", exist_ok=True)Cria as pastas, se ainda não existirem
os.path.exists("x")True se o arquivo ou a pasta existe
os.environ["NOME"] / os.environ.get("NOME", padrão)Uma variável de ambiente (com erro / sem erro)
os.name, os.sep'posix' ou 'nt'; '/' ou '\\'
sys.argvO programa e os argumentos, como lista de textos
sys.exit(n) / sys.exit("msg")Termina com o código n / com a mensagem e o código 1
print(..., file=sys.stderr)Escreve na saída de erros
sys.pathAs pastas onde o import procura, em ordem
sys.version / sys.version_infoA versão do Python, como texto / em partes
sys.platform, sys.executableO sistema; o caminho do Python em uso

Exercícios

1. A pasta atual

Complete para mostrar a pasta em que o programa está rodando:

import os print(os.())

2. Sem erro se não existir

Complete para ler a variável LOJA_MODO, com "normal" se ela não existir:

modo = os.environ.("LOJA_MODO", "normal")

3. Terminar com erro

Que número o sys.exit deve receber para dizer "deu tudo certo"?

sys.exit()

4. A Ana roda python3 loja/pasta.py estando em /home/ana. O que os.getcwd() mostra?

5. Por que um arquivo chamado random.py na pasta do programa atrapalha o import random?

6. Qual é o jeito certo de conferir se o Python é o 3.12 ou mais novo?

Missão final: o programa confere antes de começar

Missão: antes de trabalhar, o programa da lojinha confere se as pastas de que precisa existem. A pasta fotos não existe aqui. Para cada nome da lista, se os.path.exists(nome) for falso, termine com sys.exit(f"Faltou a pasta: {nome}"). Se todas existirem, mostre Tudo pronto..

import os
import sys

necessarias = ["fotos", "relatorios"]

for nome in necessarias:
    print("Conferindo", nome)

print("Tudo pronto.")
import os
import sys

necessarias = ["fotos", "relatorios"]

for nome in necessarias:
    print("Conferindo", nome)
    if not os.path.exists(nome):
        sys.exit(f"Faltou a pasta: {nome}")

print("Tudo pronto.")

Resumo

  • os conversa com o sistema; sys, com o próprio Python.
  • os.getcwd() é a pasta atual, que depende de onde o programa foi chamado; nomes sem pasta são procurados a partir dela.
  • os.listdir lista (em ordem qualquer), os.mkdir/os.makedirs criam, os.path.exists testa, os.chdir muda a pasta só do programa.
  • os.environ são as variáveis de ambiente; prefira os.environ.get("NOME", padrão).
  • sys.exit(n) termina com o código n (0 = deu certo); sys.exit("msg") mostra a mensagem e sai com 1. Por dentro, é a exceção SystemExit.
  • sys.path é onde o import procura, começando pela pasta do programa: não dê aos seus arquivos nomes de módulos do Python.
  • sys.version_info >= (3, 12) confere a versão do jeito certo.