es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

El subprocess que imprime en el seudoterminal no está utilizando el tamaño completo del terminal.

Tengo el siguiente programa que envuelve top en un seudoterminal y lo muestra de vuelta en el terminal real.

import os
import pty
import subprocess
import sys
import time

import select

stdout_master_fd, stdout_slave_fd = pty.openpty()
stderr_master_fd, stderr_slave_fd = pty.openpty()

p = subprocess.Popen(
    "top",
    shell=True,
    stdout=stdout_slave_fd,
    stderr=stderr_slave_fd,
    close_fds=True
)

stdout_parts = []
while p.poll() is None:
    rlist, _, _ = select.select([stdout_master_fd, stderr_master_fd], [], [])
    for f in rlist:
        output = os.read(f, 1000)  # Esto se usa porque no bloquea
        sys.stdout.write(output.decode("utf-8"))
        sys.stdout.flush()
    time.sleep(0.01)

Esto funciona bien y las secuencias de control se manejan como se espera. Sin embargo, el subproceso no está utilizando las dimensiones completas del terminal real.

Para comparar, ejecutando el programa anterior:

PseudoTerminal

Y ejecutando top directamente:

Direct

No encontré ninguna API de la biblioteca pty que sugiera que se pueden proporcionar dimensiones.

Las dimensiones que obtengo en la práctica para el seudoterminal son una altura de 24 líneas y un ancho de 80 columnas, estoy asumiendo que podrían estar codificadas en algún lugar.

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Solución:

    La librería pty no tiene una API directa para establecer las dimensiones del pseudo terminal. Sin embargo, podemos usar el módulo fcntl para lograr lo mismo.

    Aquí está una versión actualizada del programa que establece las dimensiones del pseudo terminal para que coincida con las dimensiones del terminal real:

    import os
    import pty
    import subprocess
    import sys
    import time
    import fcntl
    import struct
    
    import select
    
    # Obtener las dimensiones del terminal real
    altura, ancho = struct.unpack('hh', fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ, '1234'))
    
    stdout_master_fd, stdout_slave_fd = pty.openpty()
    stderr_master_fd, stderr_slave_fd = pty.openpty()
    
    # Usar fcntl para establecer las dimensiones del pseudo terminal
    fcntl.ioctl(stdout_slave_fd, termios.TIOCSWINSZ, struct.pack('hh', altura, ancho))
    
    p = subprocess.Popen(
        "top",
        shell=True,
        stdout=stdout_slave_fd,
        stderr=stderr_slave_fd,
        close_fds=True
    )
    
    stdout_parts = []
    while p.poll() is None:
        rlist, _, _ = select.select([stdout_master_fd, stderr_master_fd], [], [])
        for f in rlist:
            output = os.read(f, 1000)  # Se utiliza esto porque no bloquea
            sys.stdout.write(output.decode("utf-8"))
            sys.stdout.flush()
        time.sleep(0.01)
    

    Aquí, estamos utilizando el método fcntl.ioctl() para establecer las dimensiones del pseudo terminal. Primero usamos struct.unpack() para obtener la altura y el ancho del terminal real, y luego usamos fcntl.ioctl() para establecer estas dimensiones en el pseudo terminal usando termios.TIOCSWINSZ.

    Con estos cambios, el subprocess ahora utiliza las dimensiones completas del terminal real:

    full

Comments are closed.