Python & AI Tutorials Logo
Programación Python

29. Interactuar con el sistema operativo: sys y os

Los programas de Python no existen de forma aislada: se ejecutan en un sistema operativo que gestiona archivos, directorios, configuraciones del entorno y cómo los programas se inician y se comunican. Los módulos sys y os proporcionan herramientas para interactuar con este entorno, permitiendo que tus programas acepten argumentos de línea de comandos, lean variables de entorno, naveguen por el sistema de archivos y creen o eliminen directorios.

Comprender estos módulos transforma tus scripts de Python de código aislado en programas que pueden integrarse con el sistema en general, responder a la entrada del usuario al iniciarse y gestionar archivos y carpetas de forma programática.

29.1) Argumentos de línea de comandos y uso de sys.argv

Cuando ejecutas un script de Python desde la terminal o el símbolo del sistema, puedes pasarle información adicional; a esto se le llama argumentos de línea de comandos. Por ejemplo:

bash
python greet.py Alice 25

Aquí, greet.py es el nombre del script, y Alice y 25 son argumentos pasados al programa. El módulo sys proporciona acceso a estos argumentos a través de sys.argv, una lista que contiene el nombre del script y todos los argumentos como cadenas.

29.1.1) ¿Qué es sys.argv?

sys.argv es una lista donde:

  • sys.argv[0] es siempre el nombre del script que se está ejecutando
  • sys.argv[1], sys.argv[2], etc., son los argumentos pasados después del nombre del script
  • Todos los elementos son cadenas, incluso si parecen números

Creemos un script sencillo para ver cómo funciona esto:

python
# show_args.py
import sys
 
print("Script name:", sys.argv[0])
print("Number of arguments:", len(sys.argv))
print("All arguments:", sys.argv)

Si ejecutas este script con:

bash
python show_args.py hello world 123

Output:

Script name: show_args.py
Number of arguments: 4
All arguments: ['show_args.py', 'hello', 'world', '123']

Observa que sys.argv contiene 4 elementos: el nombre del script más tres argumentos. El número 123 se almacena como la cadena '123', no como un entero.

29.1.2) Uso de argumentos de línea de comandos en programas

Los argumentos de línea de comandos permiten que los usuarios personalicen el comportamiento del programa sin modificar el código. Aquí tienes un programa de saludo que usa el primer argumento como un nombre:

python
# greet.py
import sys
 
if len(sys.argv) < 2:
    print("Usage: python greet.py <name>")
    sys.exit(1)  # Salir con código de error
 
name = sys.argv[1]
print(f"Hello, {name}!")

Al ejecutar esto:

bash
python greet.py Alice

Output:

Hello, Alice!

Si olvidas proporcionar un nombre:

bash
python greet.py

Output:

Usage: python greet.py <name>

El programa comprueba si se proporcionaron suficientes argumentos. Si no, imprime un mensaje de uso y sale con sys.exit(1). El número 1 es un código de salida; por convención, 0 significa éxito y los valores distintos de cero indican errores. Esto ayuda a que otros programas o scripts detecten si tu programa se ejecutó correctamente.

29.1.3) Convertir argumentos a otros tipos

Como todos los argumentos llegan como cadenas, a menudo necesitas convertirlos. Aquí tienes un programa que calcula el área de un rectángulo:

python
# area.py
import sys
 
if len(sys.argv) < 3:
    print("Usage: python area.py <width> <height>")
    sys.exit(1)
 
try:
    width = float(sys.argv[1])
    height = float(sys.argv[2])
except ValueError:
    print("Error: Width and height must be numbers")
    sys.exit(1)
 
area = width * height
print(f"Area: {area}")

Al ejecutar esto:

bash
python area.py 5.5 3.2

Output:

Area: 17.6

Si el usuario proporciona una entrada no válida:

bash
python area.py five three

Output:

Error: Width and height must be numbers

El bloque try-except (del Capítulo 25) gestiona los errores de conversión con elegancia, proporcionando comentarios útiles en lugar de fallar con un traceback.

El usuario ejecuta: python script.py arg1 arg2

Python crea la lista sys.argv

sys.argv[0] = 'script.py'

sys.argv[1] = 'arg1'

sys.argv[2] = 'arg2'

El script accede a sys.argv

Procesar argumentos como cadenas

Convertir tipos si es necesario

Usar valores en la lógica del programa

29.2) Obtener información del intérprete y del tiempo de ejecución con sys

El módulo sys proporciona información sobre el propio intérprete de Python y el entorno de ejecución. Esto es útil para depuración, registro o para escribir código que se adapte a diferentes versiones de Python o plataformas.

29.2.1) Información de versión de Python

sys.version y sys.version_info te dicen qué versión de Python está ejecutando tu código:

python
import sys
 
print("Python version string:", sys.version)
print("Version info:", sys.version_info)
print(f"Major version: {sys.version_info.major}")
print(f"Minor version: {sys.version_info.minor}")

Output (example):

Python version string: 3.11.4 (main, Jul  5 2023, 13:45:01) [GCC 11.2.0]
Version info: sys.version_info(major=3, minor=11, micro=4, releaselevel='final', serial=0)
Major version: 3
Minor version: 11

sys.version es una cadena legible por humanos, mientras que sys.version_info es una tupla con nombre que puedes comparar programáticamente:

python
import sys
 
if sys.version_info < (3, 8):
    print("This program requires Python 3.8 or higher")
    sys.exit(1)
 
print("Python version is compatible")

Esto garantiza que tu programa solo se ejecute en versiones de Python compatibles.

29.2.2) Información de la plataforma

sys.platform identifica el sistema operativo:

python
import sys
 
print("Platform:", sys.platform)
 
if sys.platform == "win32":
    print("Running on Windows")
elif sys.platform == "darwin":
    print("Running on macOS")
elif sys.platform.startswith("linux"):
    print("Running on Linux")
else:
    print("Running on another platform")

Output (on Linux):

Platform: linux
Running on Linux

Esto te permite escribir código específico de la plataforma cuando sea necesario, como usar diferentes rutas de archivos o comandos del sistema.

29.2.3) Ruta de búsqueda de módulos

sys.path es una lista de directorios que Python busca cuando importas módulos:

python
import sys
 
print("Module search paths:")
for path in sys.path:
    print(f"  {path}")

Output (example):

Module search paths:
  /home/user/projects
  /usr/lib/python3.11
  /usr/lib/python3.11/lib-dynload
  /home/user/.local/lib/python3.11/site-packages

La primera entrada suele ser el directorio que contiene tu script. Python busca en estas rutas en orden cuando usas import. Comprender sys.path ayuda a depurar errores de importación o a añadir directorios de módulos personalizados.

29.2.4) Salir de programas con códigos de salida

Ya hemos visto sys.exit() usado para detener programas. Puedes pasar un código de salida para indicar éxito o fallo:

python
import sys
 
def process_data(filename):
    try:
        with open(filename) as f:
            data = f.read()
        # Procesar datos...
        return True
    except FileNotFoundError:
        print(f"Error: File '{filename}' not found", file=sys.stderr)
        return False
 
if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python script.py <filename>", file=sys.stderr)
        sys.exit(1)
    
    success = process_data(sys.argv[1])
    sys.exit(0 if success else 1)

Los códigos de salida siguen las convenciones de Unix:

  • 0 significa éxito
  • Los valores distintos de cero indican diferentes tipos de errores
  • Otros programas pueden comprobar estos códigos para determinar si tu programa tuvo éxito

29.3) Acceder a variables de entorno con os

Las variables de entorno son pares clave-valor establecidos por el sistema operativo o el usuario que los programas pueden leer. Se usan para configuración, para almacenar rutas, claves de API y otros ajustes que no deberían estar codificados de forma rígida.

29.3.1) Leer variables de entorno

El módulo os proporciona os.environ, un objeto similar a un diccionario que contiene todas las variables de entorno:

python
import os
 
# Obtener una variable de entorno específica
home = os.environ.get('HOME')  # En Unix/Linux/macOS
print(f"Home directory: {home}")
 
# Devuelve None si la variable no existe
api_key = os.environ.get('MY_API_KEY')
print(f"API key: {api_key}")

Output (on Linux):

Home directory: /home/alice
API key: None

Puedes proporcionar un valor predeterminado:

python
import os
 
# Obtener variable de entorno con valor predeterminado
log_level = os.environ.get('LOG_LEVEL', 'INFO')
print(f"Log level: {log_level}")

Output (if LOG_LEVEL not set):

Log level: INFO

29.3.2) Variables de entorno comunes

Diferentes sistemas operativos proporcionan variables de entorno estándar:

python
import os
 
# Variables multiplataforma
print("Path:", os.environ.get('PATH'))
 
# Unix/Linux/macOS
print("User:", os.environ.get('USER'))
print("Home:", os.environ.get('HOME'))
print("Shell:", os.environ.get('SHELL'))
 
# Windows
print("User", os.environ.get('USERNAME'))
print("User Profile:", os.environ.get('USERPROFILE'))
print("Temp:", os.environ.get('TEMP'))

PATH es particularmente importante: enumera directorios donde el sistema busca programas ejecutables. Cuando escribes un comando como python, el sistema busca en estos directorios.

29.3.3) Establecer variables de entorno

Puedes modificar variables de entorno para tu programa y cualquier subproceso que cree:

python
import os
 
# Establecer una variable de entorno
os.environ['MY_CONFIG'] = 'production'
 
# Leerla de nuevo
print(os.environ.get('MY_CONFIG'))  # Output: production
 
# Eliminar una variable de entorno
del os.environ['MY_CONFIG']

Importante: Los cambios en os.environ solo afectan al proceso actual de Python y a cualquier programa que lance. No persisten después de que tu programa termine ni afectan a otros programas.

29.4) Trabajar con rutas de archivos y directorios (os.path, os.getcwd)

Gestionar correctamente las rutas de archivos es crucial para programas que trabajan con archivos. Los módulos os y os.path proporcionan herramientas para construir, manipular y consultar rutas de manera independiente de la plataforma.

29.4.1) Obtener el directorio de trabajo actual

El directorio de trabajo actual (CWD) es la carpeta que tu programa considera su punto de inicio para rutas relativas:

python
import os
 
cwd = os.getcwd()
print(f"Current working directory: {cwd}")

Output (example):

Current working directory: /home/alice/projects/myapp

Cuando abres un archivo con una ruta relativa como 'data.txt', Python busca en el directorio de trabajo actual. Comprender el CWD ayuda a depurar errores de "archivo no encontrado".

29.4.2) Cambiar el directorio actual

Puedes cambiar el directorio de trabajo con os.chdir():

python
import os
 
original = os.getcwd()
print("Original directory:", original)
 
# Cambiar a un directorio diferente
os.chdir('/tmp')
print("New directory:", os.getcwd())
 
# Volver atrás
os.chdir(original)
print("Back to:", os.getcwd())

Output:

Original directory: /home/alice/projects
New directory: /tmp
Back to: /home/alice/projects

Nota: En el Capítulo 28, aprendiste sobre contextlib.chdir(), que restaura automáticamente el directorio original. Para cambios simples de directorio, prefiere usar el gestor de contexto:

python
from contextlib import chdir
 
with chdir('/tmp'):
    print("Temporarily in:", os.getcwd())
# Restaurado automáticamente

Esto garantiza que el directorio siempre se restaure, incluso si ocurre un error.

29.4.3) Construir rutas con os.path.join()

Los distintos sistemas operativos usan distintos separadores de ruta:

  • Unix/Linux/macOS: / (barra inclinada)
  • Windows: \ (barra invertida)

os.path.join() construye rutas correctamente para la plataforma actual:

python
import os
 
# Construir una ruta hacia un archivo en un subdirectorio
data_dir = 'data'
filename = 'users.txt'
filepath = os.path.join(data_dir, filename)
 
print(f"File path: {filepath}")

Output (on Unix/Linux/macOS):

File path: data/users.txt

Output (on Windows):

File path: data\users.txt

Puedes unir varios componentes:

python
import os
 
base = '/home/alice'
project = 'myapp'
subdir = 'data'
file = 'config.json'
 
full_path = os.path.join(base, project, subdir, file)
print(full_path)  # Output: /home/alice/myapp/data/config.json

Usar os.path.join() hace que tu código sea portátil entre sistemas operativos.

29.4.4) Comprobar si existen rutas

Antes de trabajar con archivos o directorios, comprueba si existen:

python
import os
 
path = 'data.txt'
 
if os.path.exists(path):
    print(f"'{path}' exists")
else:
    print(f"'{path}' does not exist")

También puedes comprobar específicamente si son archivos o directorios:

python
import os
 
path = 'mydir'
 
if os.path.isfile(path):
    print(f"'{path}' is a file")
elif os.path.isdir(path):
    print(f"'{path}' is a directory")
elif os.path.exists(path):
    print(f"'{path}' exists but is neither a file nor directory")
else:
    print(f"'{path}' does not exist")

Estas comprobaciones evitan errores al intentar abrir archivos inexistentes o listar directorios inexistentes.

29.4.5) Obtener rutas absolutas

os.path.abspath() convierte rutas relativas en rutas absolutas:

python
import os
 
relative_path = 'data/users.txt'
absolute_path = os.path.abspath(relative_path)
 
print(f"Relative: {relative_path}")
print(f"Absolute: {absolute_path}")

Output (example):

Relative: data/users.txt
Absolute: /home/alice/projects/myapp/data/users.txt

Esto es útil para registro, mensajes de error o cuando necesitas saber la ubicación exacta de un archivo.

29.4.6) Dividir rutas en componentes

os.path.split() separa una ruta en directorio y nombre de archivo:

python
import os
 
path = '/home/alice/projects/data.txt'
directory, filename = os.path.split(path)
 
print(f"Directory: {directory}")
print(f"Filename: {filename}")

Output:

Directory: /home/alice/projects
Filename: data.txt

os.path.basename() obtiene solo el nombre del archivo, y os.path.dirname() obtiene solo el directorio:

python
import os
 
path = '/home/alice/projects/data.txt'
 
print(f"Basename: {os.path.basename(path)}")  # Output: data.txt
print(f"Dirname: {os.path.dirname(path)}")    # Output: /home/alice/projects

29.4.7) Dividir extensiones de archivo

os.path.splitext() separa el nombre del archivo de su extensión:

python
import os
 
filename = 'report.pdf'
name, extension = os.path.splitext(filename)
 
print(f"Name: {name}")        # Output: report
print(f"Extension: {extension}")  # Output: .pdf

Esto es útil para procesar archivos según su tipo:

python
import os
 
files = ['data.csv', 'image.png', 'document.txt', 'script.py']
 
for file in files:
    name, ext = os.path.splitext(file)
    if ext == '.csv':
        print(f"Process CSV file: {file}")
    elif ext == '.png':
        print(f"Process image file: {file}")

Output:

Process CSV file: data.csv
Process image file: image.png

29.5) Listar, crear y eliminar archivos y directorios

El módulo os proporciona funciones para manipular el sistema de archivos: listar el contenido de directorios, crear nuevos directorios y eliminar archivos y carpetas.

29.5.1) Listar el contenido de un directorio

os.listdir() devuelve una lista de todos los elementos en un directorio:

python
import os
 
# Listar el contenido del directorio actual
contents = os.listdir('.')
print("Current directory contents:")
for item in contents:
    print(f"  {item}")

Output (example):

Current directory contents:
  script.py
  data.txt
  mydir
  README.md

La lista incluye tanto archivos como directorios. Para distinguirlos:

python
import os
 
contents = os.listdir('.')
print("Files:")
for item in contents:
    if os.path.isfile(item):
        print(f"  {item}")
 
print("\nDirectories:")
for item in contents:
    if os.path.isdir(item):
        print(f"  {item}")

Output:

Files:
  script.py
  data.txt
  README.md
 
Directories:
  mydir

29.5.2) Crear directorios

os.mkdir() crea un único directorio:

python
import os
 
new_dir = 'output'
 
if not os.path.exists(new_dir):
    os.mkdir(new_dir)
    print(f"Created directory: {new_dir}")
else:
    print(f"Directory already exists: {new_dir}")

Output:

Created directory: output

Importante: os.mkdir() falla si el directorio padre no existe. Por ejemplo, intentar crear 'data/output' cuando 'data' no existe generará un error.

os.makedirs() crea todos los directorios padre necesarios:

python
import os
 
nested_dir = 'data/processed/2024'
 
if not os.path.exists(nested_dir):
    os.makedirs(nested_dir)
    print(f"Created directory structure: {nested_dir}")

Output:

Created directory structure: data/processed/2024

Esto crea data, luego data/processed, y luego data/processed/2024 si no existen.

29.5.3) Eliminar archivos

os.remove() elimina un archivo:

python
import os
 
filename = 'temp.txt'
 
# Crear un archivo temporal
with open(filename, 'w') as f:
    f.write('Temporary data')
 
print(f"File exists: {os.path.exists(filename)}")  # Output: True
 
# Eliminar el archivo
os.remove(filename)
print(f"File exists: {os.path.exists(filename)}")  # Output: False

Advertencia: os.remove() elimina archivos de forma permanente; no van a una papelera de reciclaje.

29.5.4) Eliminar directorios

os.rmdir() elimina un directorio vacío:

python
import os
 
directory = 'empty_dir'
 
# Crear y luego eliminar un directorio vacío
os.mkdir(directory)
print(f"Created: {directory}")
 
os.rmdir(directory)
print(f"Removed: {directory}")

os.rmdir() falla si el directorio contiene archivos. Para eliminar un directorio y todo su contenido, necesitas eliminar los archivos primero:

python
import os
 
def remove_directory_contents(directory):
    """Eliminar todos los archivos de un directorio y luego eliminar el directorio.
    
    Nota: falla si el directorio contiene subdirectorios.
    """
    if not os.path.exists(directory):
        print(f"Directory does not exist: {directory}")
        return
    
    # Eliminar todos los archivos del directorio
    for item in os.listdir(directory):
        item_path = os.path.join(directory, item)
        if os.path.isfile(item_path):
            os.remove(item_path)
            print(f"Removed file: {item_path}")
    
    # Eliminar el directorio ahora vacío
    os.rmdir(directory)
    print(f"Removed directory: {directory}")
 
# Ejemplo de uso
test_dir = 'test_data'
os.makedirs(test_dir, exist_ok=True)
 
# Crear algunos archivos de prueba
with open(os.path.join(test_dir, 'file1.txt'), 'w') as f:
    f.write('test')
with open(os.path.join(test_dir, 'file2.txt'), 'w') as f:
    f.write('test')
 
# Eliminar todo
remove_directory_contents(test_dir)

Output:

Removed file: test_data/file1.txt
Removed file: test_data/file2.txt
Removed directory: test_data

Nota: Para una eliminación de directorios más compleja (incluyendo subdirectorios), el módulo shutil proporciona shutil.rmtree(), pero eso está fuera de nuestro alcance actual.

29.5.5) Renombrar archivos y directorios

os.rename() renombra o mueve archivos y directorios:

python
import os
 
# Renombrar un archivo
old_name = 'draft.txt'
new_name = 'final.txt'
 
# Crear archivo de prueba
with open(old_name, 'w') as f:
    f.write('content')
 
os.rename(old_name, new_name)
print(f"Renamed '{old_name}' to '{new_name}'")

También puedes mover archivos a diferentes directorios:

python
import os
 
# Crear directorios y archivo
os.makedirs('source', exist_ok=True)
os.makedirs('destination', exist_ok=True)
 
with open('source/file.txt', 'w') as f:
    f.write('content')
 
# Mover archivo a un directorio diferente
os.rename('source/file.txt', 'destination/file.txt')
print("Moved file to destination directory")

Los módulos sys y os le dan a tus programas de Python la capacidad de interactuar con el sistema operativo, aceptar entrada de la línea de comandos, leer configuración y gestionar archivos y directorios. Estas capacidades transforman scripts simples en potentes herramientas de línea de comandos que se integran sin problemas con el entorno más amplio del sistema.


© 2025. Primesoft Co., Ltd.
support@primesoft.ai