El módulo posix expone llamadas de sistema comunes en plataformas compatibles con POSIX. Proporciona una interfaz de bajo nivel para archivos, directorios, procesos, descriptores, permisos, usuarios, grupos e información del sistema operativo. En la práctica, casi todo código de aplicación debería importar os, porque ofrece una capa más portable e incluye la mayor parte de la API útil de posix.
Conocer posix, sin embargo, ayuda a entender cómo Python se comunica con sistemas Unix como Linux, macOS y BSD. También resulta útil al investigar comportamientos específicos de la plataforma, crear herramientas administrativas, comparar builds del intérprete o comprender el origen de muchas funciones de os.
Disponibilidad y portabilidad
posix solo existe cuando Python fue compilado para un sistema que ofrece la interfaz correspondiente. Normalmente no está disponible en Windows. Por eso, una biblioteca multiplataforma no debería importarlo globalmente sin una alternativa.
try:
import posix
except ImportError:
posix = None
if posix is None:
print("La interfaz POSIX no está disponible")
Incluso en Unix, las funciones individuales pueden variar según el kernel, la biblioteca C, las opciones de compilación y la versión de Python. Comprueba capacidades con hasattr() o, preferiblemente, con los conjuntos publicados por os.
Por qué conviene usar os
El módulo os selecciona la implementación adecuada para el sistema actual. En Unix, muchas de sus funciones se apoyan en posix; en Windows, otra implementación ofrece operaciones equivalentes. Así, os.open(), os.stat() y os.getpid() mantienen una interfaz pública consistente.
import os
print(os.getpid())
print(os.getcwd())
Importa posix directamente solo cuando el objetivo sea estudiar, probar o depender de comportamiento POSIX. Para programas normales, os es más claro y seguro.
Descriptores de archivo
Las llamadas de bajo nivel trabajan con descriptores enteros. open() abre una ruta y devuelve un descriptor; read() y write() transfieren bytes; close() libera el recurso.
import os
fd = os.open("datos.bin", os.O_RDONLY)
try:
bloque = os.read(fd, 4096)
print(len(bloque))
finally:
os.close(fd)
El bloque finally es esencial cuando gestionas descriptores manualmente. Para archivos normales, la función global open() con with es más cómoda porque gestiona cierre, buffering, texto y encoding.
Flags de apertura
Las llamadas POSIX combinan flags como O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_EXCL, O_APPEND y, cuando existe, O_CLOEXEC. El operador bit a bit | construye la configuración.
import os
flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL
fd = os.open("nuevo.txt", flags, 0o600)
try:
os.write(fd, b"contenido privado\n")
finally:
os.close(fd)
O_EXCL junto con O_CREAT evita reemplazar un archivo existente y reduce condiciones de carrera. El modo 0o600 solicita acceso solo para el propietario, aunque la umask del proceso también afecta el permiso final.
Rutas como str o bytes
En Unix, una ruta puede expresarse como str o bytes. Usa texto en la mayoría de los programas. Los bytes son útiles cuando necesitas conservar nombres que no pueden decodificarse con el encoding del sistema de archivos.
No mezcles ambos tipos en una operación. Las funciones que reciben una ruta en bytes normalmente devuelven nombres en bytes. os.fsencode() y os.fsdecode() convierten de acuerdo con la política del sistema de archivos de Python.
Información de archivos con stat
stat() devuelve tamaño, timestamps, propietario, grupo, modo y otros campos. Usa el módulo stat para interpretar los bits del modo.
import os
import stat
info = os.stat("datos.bin", follow_symlinks=False)
print(info.st_size)
print(stat.filemode(info.st_mode))
print(stat.S_ISREG(info.st_mode))
Cuando la seguridad depende del objeto inspeccionado, evita la secuencia “comprobar una ruta y después abrirla”. Otro proceso podría sustituirla entre ambas operaciones. Prefiere APIs basadas en descriptores y parámetros como dir_fd y follow_symlinks cuando estén disponibles.
Enlaces simbólicos
stat() suele seguir enlaces simbólicos, mientras lstat() describe el propio enlace. La diferencia es importante en scanners, backups, instaladores y herramientas de limpieza.
import os
destino = os.readlink("acceso")
info_enlace = os.lstat("acceso")
print(destino, info_enlace.st_mode)
Nunca supongas que una ruta confiable sigue apuntando al mismo objeto. En directorios compartidos, un atacante puede cambiar un symlink y redirigir una operación privilegiada.
Permisos y umask
chmod() cambia bits de permiso. umask() define qué permisos solicitados se eliminan al crear objetos. Como la umask es estado global del proceso, modificarla en una aplicación con varias threads es arriesgado.
import os
os.chmod("nuevo.txt", 0o600)
No uses chmod(0o777) como arreglo universal. Concede únicamente lo necesario y considera ACL, políticas del container, volúmenes montados e identidad efectiva.
Usuario, grupo y proceso
Funciones como getpid(), getppid(), getuid(), geteuid(), getgid() y getegid() describen el proceso. La identidad real y efectiva pueden diferir en programas con privilegios especiales.
import os
print({
"pid": os.getpid(),
"uid": os.getuid(),
"euid": os.geteuid(),
"gid": os.getgid(),
})
Para convertir UID y GID en nombres, consulta pwd en Python y grp en Python. Esas bases de cuentas no son mecanismos de autenticación.
Variables de entorno
En POSIX, el entorno es una colección de claves y valores asociada al proceso. En Python, prefiere os.environ, un mapeo mutable cuyas modificaciones serán heredadas por futuros procesos hijos.
import os
modo = os.environ.get("APP_MODE", "development")
os.environ["APP_CHILD_FLAG"] = "1"
No registres todo el entorno. Puede contener tokens, contraseñas, endpoints privados y rutas sensibles. Valida los valores antes de usarlos en comandos o nombres de archivo.
Creación de procesos
POSIX ofrece primitivas como fork(), execve(), waitpid() y _exit(). Son poderosas, pero exigen controlar threads, buffers, locks y descriptores heredados.
Para ejecutar programas, prefiere subprocess. Su API gestiona argumentos, redirección, códigos de salida, timeouts y cierre de descriptores de forma más segura.
import subprocess
resultado = subprocess.run(
["uname", "-s"],
check=True,
capture_output=True,
text=True,
timeout=5,
)
print(resultado.stdout.strip())
Evita shell=True con datos no confiables. Pasa los argumentos como lista.
Fork y threads
Después de fork(), solo continúa en el hijo la thread que llamó a la función. Locks mantenidos por otras threads pueden quedar bloqueados para siempre. Clientes de bases de datos, logging, TLS y allocators también pueden conservar estados inconsistentes.
Las aplicaciones modernas deberían usar subprocess o un método de inicio adecuado de multiprocessing. Evita trabajo Python complejo entre fork() y exec() en procesos multithread.
Descriptores heredados
Un descriptor abierto puede filtrarse a un proceso hijo y mantener archivos, sockets o pipes activos. Python crea muchos descriptores como no heredables por defecto, pero extensiones nativas y configuraciones explícitas pueden cambiarlo.
Usa os.get_inheritable(), os.set_inheritable() y opciones de subprocess conscientemente. fcntl en Python explica flags y locks de descriptores Unix.
Operaciones relativas a directorios
Muchas funciones aceptan dir_fd. En lugar de concatenar rutas, abre un directorio confiable y resuelve nombres respecto de su descriptor. Esto puede reducir carreras y facilitar operaciones restringidas.
import os
base_fd = os.open("datos", os.O_RDONLY | os.O_DIRECTORY)
try:
fd = os.open("item.txt", os.O_RDONLY, dir_fd=base_fd)
try:
print(os.read(fd, 100))
finally:
os.close(fd)
finally:
os.close(base_fd)
No toda función o plataforma soporta dir_fd. Consulta os.supports_dir_fd.
Sincronización y durabilidad
fsync() solicita que el sistema escriba datos y metadatos asociados al descriptor. Para reemplazos críticos, escribe un archivo temporal en el mismo sistema de archivos, sincronízalo, renómbralo atómicamente y, cuando corresponda, sincroniza el directorio.
Una llamada exitosa no protege contra toda falla de hardware o caché. La durabilidad depende del sistema de archivos, dispositivo, opciones de montaje e infraestructura.
Errores y OSError
Las fallas de llamadas del sistema aparecen como subclases de OSError, entre ellas FileNotFoundError, PermissionError, FileExistsError e IsADirectoryError.
from pathlib import Path
try:
datos = Path("config.ini").read_text(encoding="utf-8")
except FileNotFoundError:
datos = ""
except PermissionError as error:
raise RuntimeError("sin permiso para leer config.ini") from error
Captura la excepción más específica que permita responder de manera útil. No ocultes fallas inesperadas con except OSError: pass.
Límites de recursos
Las llamadas POSIX pueden fallar por agotamiento de descriptores, memoria, espacio en disco o límites de procesos. resource en Python explica cómo consultar y definir varios límites Unix.
Gestiona errores, configura timeouts y limita el volumen de entrada. Un recorrido de directorios o un proceso batch debería cerrar recursos progresivamente.
Pruebas en sistemas reales
Los containers no reproducen todas las diferencias entre macOS, Linux y BSD. Prueba permisos, symlinks, rutas en bytes, mounts de solo lectura, sistemas de archivos de red, disco lleno, UIDs distintos, umask, señales y herencia de descriptores.
Ejecuta pruebas con privilegios reducidos. Probar solo como administrador puede ocultar errores de permisos y suposiciones inseguras.
Errores comunes
Los problemas frecuentes incluyen importar posix cuando os sería suficiente, suponer que todas las funciones existen, olvidar cerrar descriptores, mezclar rutas de texto y bytes, seguir symlinks sin intención, cambiar la umask global desde varias threads, usar fork() sin seguridad y capturar OSError sin diagnóstico.
Conclusión
posix muestra la capa de llamadas de sistema Unix utilizada por Python, pero os debería seguir siendo la interfaz predeterminada para la mayoría de los proyectos. Usa APIs de alto nivel cuando expresen mejor la intención y recurre a descriptores, flags y operaciones relativas a directorios cuando realmente necesites control preciso.
Valida capacidades, cierra recursos, reduce privilegios y trata las rutas compartidas como mutables. Consulta la documentación oficial de posix y la documentación de os.







