8 min de lectura

¿Cuándo cambia un comando la asignación de TTY en SSH?

La asignación de TTY en SSH cambia avisos, flujos, señales y detección de terminal. Aprende cuándo usar -T, -t o -tt sin romper la automatización.

¿Cuándo cambia un comando la asignación de TTY en SSH?

Añadir -t a un comando SSH hace mucho más que mostrar un aviso. Sustituye tres flujos remotos separados por un terminal, instala las reglas de línea del terminal, entrega al proceso un terminal de control y anima a los programas a comportarse como si una persona estuviera mirando. Eso puede arreglar una ejecución interactiva de sudo y, al mismo tiempo, romper sin ruido un analizador, una tubería o la cancelación.

Para trabajos desatendidos, el valor predeterminado debe ser no usar PTY. Solicítalo solo cuando el programa remoto necesite de verdad la semántica de un terminal y trata esa decisión como parte del contrato del comando. He visto demasiados scripts de despliegue adquirir -tt durante una emergencia y conservarlo durante años, mucho después de que alguien recordara qué fallo ocultaba.

Un PTY cambia el entorno del proceso

La asignación de TTY en SSH cambia los descriptores de archivo que recibe el proceso remoto, no solo el aspecto de su salida. Sin PTY, OpenSSH conecta la entrada estándar, la salida estándar y el error estándar mediante tuberías o pares de sockets. Con PTY, OpenSSH lo convierte en el terminal de control y duplica el mismo descriptor de terminal en los tres flujos estándar.

Ese detalle de implementación tiene consecuencias visibles. Un programa puede llamar a isatty() y elegir una ruta interactiva. El controlador del terminal puede procesar caracteres de entrada especiales, repetir la entrada, convertir finales de línea y seguir un grupo de procesos en primer plano. El error estándar deja de tener un canal remoto independiente porque ambos descriptores de salida apuntan al mismo terminal.

RFC 4254 mantiene estas ideas separadas en el protocolo. Una sesión puede solicitar pty-req y después pedir un shell o un comando exec. La solicitud de PTY contiene un tipo de terminal, dimensiones y modos de terminal codificados. Nada en esa solicitud convierte una petición exec en un shell de inicio de sesión.

OpenSSH presenta la elección con tres formas útiles:

  • ssh -T host command desactiva expresamente la asignación de PTY.
  • ssh -t host command solicita un PTY cuando el cliente local dispone de terminal.
  • ssh -tt host command fuerza la solicitud aunque la entrada local sea una tubería u otra fuente que no sea un terminal.

El doble -t no crea un terminal remoto más potente. Omite la comprobación de seguridad local. La diferencia importa en un ejecutor de compilación, un proceso agente o printf ... | ssh, donde un solo -t puede imprimir “Pseudo-terminal will not be allocated because stdin is not a terminal” y continuar sin la semántica que esperaba quien escribió el comando.

No usar PTY también conserva una ruta transparente para los bytes. El manual ssh(1) de OpenSSH considera este modo adecuado para transferir datos binarios con fiabilidad. Un PTY es un dispositivo de caracteres sujeto a reglas de procesamiento, por lo que es un transporte incorrecto para un archivo comprimido, un volcado de base de datos o una salida para máquinas cuyos bytes deben mantenerse exactos.

La misma elección puede quedar oculta en la configuración. La opción de cliente RequestTTY de OpenSSH acepta no, yes, force o auto, que corresponden a los comportamientos que suelen obtenerse con -T, -t y el valor predeterminado. Comprueba la configuración efectiva con ssh -G host.example cuando un comando recibe un terminal que no pidió en la línea de comandos. Los bloques de host y los archivos incluidos pueden convertir dos comandos aparentemente iguales en sesiones distintas.

El servidor también decide. PermitTTY puede rechazar la asignación y una entrada de authorized key puede incluir la restricción no-pty. Un comando forzado se ejecuta sobre un PTY solo si el cliente lo solicita y el servidor lo permite. Trata el rechazo como una incompatibilidad real de interfaz, no como un motivo para reintentar con más opciones -t.

Mide ambos modos antes de cambiar nada

Una sonda pequeña revela más que otra ronda de adivinanzas sobre opciones de SSH. Ejecútala con la misma cuenta, configuración de host y ruta de comandos que utiliza producción:

probe='
for fd in 0 1 2; do
    if test -t "$fd"; then kind=tty; else kind=not-tty; fi
    printf "fd%s=%s\n" "$fd" "$kind"
done
printf "term=%s\n" "${TERM-unset}"
printf "stdout-marker\n"
printf "stderr-marker\n" >&2
exit 23
'

ssh -T host.example "$probe" >no-pty.out 2>no-pty.err
printf 'no-pty ssh status=%s\n' "$?"

ssh -tt host.example "$probe" >pty.out 2>pty.err
printf 'pty ssh status=%s\n' "$?"

La ejecución sin terminal debe escribir las tres líneas fdN=not-tty, term=unset y stdout-marker en no-pty.out. Debe escribir solo stderr-marker en no-pty.err. El valor exacto de TERM puede variar porque clientes y servidores aceptan ajustes de entorno de formas distintas, así que registra lo que entrega tu ruta real en lugar de depender del ejemplo.

La ejecución con PTY debe declarar los tres descriptores como tty. Los dos marcadores suelen llegar a pty.out, a menudo con finales de línea formados por retorno de carro y salto de línea. pty.err contiene diagnósticos locales de SSH, si los hay, pero no puede recuperar el error estándar original del programa remoto como flujo separado. Ambos comandos SSH deben devolver 23 porque asignar un PTY no descarta por sí solo el estado de salida remoto.

Amplía la sonda con el ejecutable real antes de cambiar un trabajo. Añade command -V tool, pwd, una impresión filtrada del entorno y las opciones de diagnóstico sin secretos del programa. Si la salida cambia, identifica qué observación provocó la rama: detección de terminal, TERM, anchura del terminal, flujos combinados, un archivo de inicio o un aviso. “Funciona con -t” solo describe un síntoma.

Ejecuta también la sonda mediante el mismo lanzador. Un comando pegado en un shell tiene TTY local; un agente o un trabajador de integración continua no suele tenerlo. Por eso un experimento con -t ante un teclado puede diferir de la ejecución automática hasta que pruebas -tt, y por eso forzar un PTY puede exponer un trabajo a datos de entrada que nunca esperaba.

Prueba la entrada aparte de la salida. ssh -n redirige la entrada estándar del cliente desde /dev/null, y la opción StdinNull hace lo mismo en la configuración. Resulta útil cuando un comando remoto nunca debe consumir la entrada del llamador, pero no desactiva por sí sola la asignación de PTY. Un PTY forzado con entrada nula sigue cambiando la detección de terminal, la mezcla de flujos y el comportamiento al colgar.

Ten cuidado al ejecutar SSH dentro de un bucle. Sin -n, el primer comando remoto puede leer líneas destinadas al bucle, aunque el proceso remoto no pretendiera consumirlas. Con PTY, el eco del terminal también puede devolver esos bytes a la transcripción. Define quién controla la entrada estándar antes de interpretar cualquier otra diferencia entre ejecuciones.

Los avisos de sudo necesitan un contrato explícito

sudo necesita un medio para autenticar y un PTY le ofrece un terminal desde el que leer una contraseña. El manual de sudo dice que, por regla general, lee la contraseña del terminal del usuario. Sin uno, un requisito de contraseña falla a menos que exista un ayudante askpass o el llamador elija otro método de entrada.

Eso explica el arreglo habitual:

ssh -t host.example 'sudo systemctl restart example.service'

Es aceptable para una persona que piensa escribir una contraseña y observar el comando. Es una mala reparación para una ejecución desatendida. El trabajo puede esperar indefinidamente, un aviso puede contaminar la salida esperada y alguien puede acabar enviando una contraseña por el mismo canal que transporta los datos del comando.

Usa sudo no interactivo para automatizar:

ssh -T host.example \
  'sudo -n /usr/bin/systemctl restart example.service'

La opción -n indica a sudo que no pregunte. Si las credenciales en caché o la política sudoers no autorizan la acción sin interacción, sudo termina con un error. Ese fallo es útil: el llamador recibe un estado definido en vez de un aviso oculto. Combínalo con una regla sudoers limitada a un comando y unos argumentos exactos cuando la automatización con privilegios sea necesaria. Permitir un shell completo sin contraseña cambia un problema de disponibilidad por otro de autoridad mucho mayor.

No dependas de una marca de tiempo de sudo almacenada para un trabajo desatendido. La caché pertenece a un contexto de autenticación cuyos detalles de terminal y sesión varían según la política. Si un trabajo funciona porque un administrador usó sudo un minuto antes y falla tras un fin de semana tranquilo, no tiene un diseño de autorización, sino suerte con el momento.

sudo -S lee una contraseña desde la entrada estándar. Puede hacer funcionar un comando sin PTY, pero mezcla un secreto con la ruta de datos y entrega al llamador la gestión de la contraseña. Evítalo en agentes y automatizaciones habituales. Un ayudante askpass puede ser adecuado en un flujo gráfico atendido por una persona, pero sigue siendo autenticación interactiva y no debe improvisarse dentro de un trabajo supuestamente desatendido.

Aquí suelen confundirse dos PTY. SSH puede asignar un PTY remoto antes de iniciar sudo. Por separado, sudo moderno puede ejecutar el comando autorizado en su propio PTY para registrar E/S y aislarlo; sudo 1.9.14 activa su opción use_pty por defecto. Ese PTY interior no proporciona el aviso exterior de contraseña cuando la sesión SSH no tiene terminal. Comienza después de que sudo tenga contexto suficiente para ejecutar el comando.

Algunas configuraciones de sudoers también exigen un terminal como política. Las configuraciones empresariales antiguas solían usar requiretty, y un sistema actual aún puede conservarlo. Confirma la política efectiva de sudoers en vez de suponer que cada mensaje “terminal is required” señala un aviso de contraseña.

Un PTY no elige los archivos de inicio del shell

Un comando SSH con PTY sigue siendo un comando ejecutado por el shell configurado para la cuenta mediante -c. El manual sshd(8) de OpenSSH dice que el comando solicitado se ejecuta así, y el código del servidor se lo entrega al shell del usuario. La asignación de PTY cambia los descriptores que rodean ese shell; no añade -i, -l ni una opción de inicio de sesión.

Esto importa cuando PATH, un gestor de lenguajes o un alias existe en el aviso interactivo, pero no en la automatización. Añadir -t puede parecer que arregla la ruta porque un archivo de inicio contiene pruebas de terminal o porque la herramienta llamada detecta el terminal. También puede no hacer nada. Depender de ello acopla el trabajo a archivos que los desarrolladores editan para sus propios terminales.

Bash tiene un caso especial que complica estas creencias. Su manual dice que un shell interactivo de inicio de sesión lee archivos de perfil, que uno interactivo sin inicio lee .bashrc y que uno no interactivo usa BASH_ENV. Bash también intenta reconocer cuándo lo ejecuta un daemon de shell remoto y puede leer .bashrc aunque no sea interactivo, salvo que se invoque como sh. Es un comportamiento de Bash, no una promesa de SSH, y no puede trasladarse a cualquier shell de cuenta.

Selecciona el modo del shell directamente cuando lo necesites:

# A predictable noninteractive Bash command with explicit inputs
ssh -T host.example \
  'PATH=/usr/local/bin:/usr/bin:/bin /bin/bash -c '\''command -v deploy && deploy'\'''

# A login environment, requested because the command truly depends on it
ssh -T host.example \
  '/bin/bash -lc '\''command -v deploy && deploy'\'''

La segunda forma lee deliberadamente los archivos de inicio de sesión y hereda sus riesgos: una salida impresa por un perfil puede corromper un protocolo y un perfil puede cambiar el comportamiento sin revisión del despliegue. Para trabajos de producción, una ruta absoluta al ejecutable y un entorno pequeño y explícito suelen ser mejores.

Los alias son otra trampa. Bash no interactivo no expande alias salvo que expand_aliases esté activado, y una función de shell solo existe si un mecanismo de inicio la define o importa. Si ssh host deploy funciona únicamente tras añadir -t, comprueba que deploy sea un ejecutable real. Un terminal no debe decidir si la cuenta remota puede encontrar el programa.

Recuerda que SSH envía una cadena de comando, no un vector de argumentos para el ejecutable final. El shell de la cuenta remota analiza esa cadena después de que el shell local haya procesado sus propias comillas. La asignación de PTY no cambia ninguno de los dos análisis. Cuando los valores puedan contener espacios o metacaracteres del shell, envía un script con entradas fijas, usa un ayudante remoto con un formato de datos definido o cita cada capa de forma deliberada. Un terminal no puede reparar un argumento que el shell local expandió demasiado pronto.

Ctrl-C sigue las reglas del terminal solo con PTY

Separa aprobaciones y avisos sudo
Sallyport aprueba la sesión del agente localmente, fuera del flujo del terminal remoto.

Con un PTY, Ctrl-C suele ser un byte de entrada interpretado por el controlador del terminal remoto. POSIX lo llama carácter INTR. Cuando está activa la marca ISIG, el controlador descarta el byte y envía SIGINT a cada proceso del grupo en primer plano del terminal. Por eso una tubería remota en primer plano puede detenerse como una sola tarea.

El cliente SSH local coloca el terminal local en un modo adecuado y envía las pulsaciones por el canal. El PTY remoto controla la entrada canónica, el eco, los caracteres especiales y el tamaño de ventana. Los programas como editores de pantalla completa pueden cambiar esos modos, y una desconexión anormal puede dejar la pantalla local con aspecto incorrecto hasta que se restablezca el terminal.

Sin PTY, no hay controlador de terminal remoto que interprete Ctrl-C ni grupo en primer plano asociado a un terminal. RFC 4254 define una solicitud separada de canal SSH signal, pero también permite que los sistemas sin señales la ignoren. Por eso un cliente, servidor, envoltorio y programa llamado pueden producir una cancelación distinta de la de un terminal interactivo.

Ctrl-Z y el control de tareas revelan la diferencia todavía antes. En un terminal, el carácter SUSP puede enviar SIGTSTP al grupo en primer plano y un shell interactivo puede reanudar la tarea más tarde. Un comando remoto de una sola ejecución no adquiere una conversación útil de control de tareas solo por tener PTY. Suspenderlo puede dejar al cliente SSH esperando un grupo remoto detenido, sin un aviso de shell desde el que ejecutar fg.

No consideres segura una transacción remota por suponer que el operador podrá pulsar Ctrl-C en el momento justo. Define la cancelación en el comando remoto. Un envoltorio de shell puede capturar señales y terminar su grupo de hijos, un gestor de servicios puede ser dueño del proceso y un tiempo límite remoto puede acotar la ejecución. Después prueba la desconexión, no solo el teclado.

ssh -tt host.example '
  trap '\''printf "wrapper got INT\n" >&2; exit 130'\'' INT
  printf "remote shell pid=%s\n" "$$"
  sleep 300
'

Pulsar Ctrl-C debe ejercitar la ruta PTY y devolver el control. Repite la prueba con el programa real porque shells, aplicaciones de terminal y supervisores instalan manejadores distintos. Prueba también cerrar la conexión de red. Desmontar un PTY puede generar un cuelgue para la sesión controlada, mientras que un hijo sin PTY que conserve una tubería de salida puede mantener abierto el canal SSH. Poner un proceso en segundo plano no es un plan de separación en ninguno de los dos modos.

Para trabajos largos, envíalos a un gestor de servicios o sistema de tareas remoto y devuelve un identificador. La cancelación tendrá así un destino remoto explícito y SSH solo informará de si el envío tuvo éxito. También evita que una breve caída del cliente decida si continúa la mitad de una migración.

El estado de salida se conserva, pero los envoltorios pueden sustituirlo

OpenSSH devuelve el estado de salida del comando remoto en ambos modos. Su manual de cliente dice que ssh termina con ese estado, o con 255 cuando ocurre un error. RFC 4254 describe el mensaje de canal exit-status como un valor sin signo de 32 bits y un mensaje exit-signal separado para terminaciones por señal.

La asignación de PTY no vuelve más fiable un estado correcto. La composición del shell determina qué estado pasa a ser el del comando remoto. Este comando informa del estado de printf, por lo que puede ocultar un despliegue fallido:

ssh -tt host.example 'deploy; printf "finished\n"'

Conserva el resultado de forma expresa:

ssh -T host.example '
  deploy
  rc=$?
  printf "deploy_status=%s\n" "$rc" >&2
  exit "$rc"
'
rc=$?
printf 'ssh_status=%s\n' "$rc"
exit "$rc"

Las tuberías locales pueden volver a ocultarlo. En shells sin una opción de estado de tubería, ssh host command | tee log suele devolver el estado de tee. Captura primero la salida SSH en un archivo, usa un shell con una función de estado de tuberías comprobada o lee los estados de cada comando. No supongas que set -e arregla todas las tuberías, condiciones o subshells.

El estado 255 es ambiguo porque OpenSSH lo reserva para errores del cliente, mientras un programa remoto también puede salir con 255. Si la distinción importa, haz que el envoltorio remoto emita un registro estructurado de finalización por un canal protegido o asigne los estados de la aplicación a un intervalo acordado. Un fallo de autenticación, un fallo al verificar el host, la pérdida del transporte y un 255 remoto literal no deben provocar el mismo reintento.

Los fallos al establecer la conexión ocurren antes de que el envoltorio remoto pueda imprimir nada. Usa tiempos límite del cliente y suficientes diagnósticos SSH para clasificarlos en local, pero mantén esos diagnósticos fuera del archivo de datos del programa. Cuando el servidor inicie el envoltorio, incluye un identificador de ejecución y un registro de estado final para distinguir “nunca empezó” de “empezó y se perdió la conexión”. Esa diferencia evita reintentos ciegos de comandos que quizá ya cambiaron el estado.

Las muertes por señal requieren el mismo cuidado. Un shell suele representar una señal como 128 más su número, pero el protocolo SSH puede informar directamente de una señal de salida y el cliente no tiene por qué parecerse siempre al estado de un hijo de un shell local. Define los estados que emite tu envoltorio en vez de intentar descifrar todos los valores superiores a 128 después de una incidencia.

Un PTY mezcla flujos y modifica bytes

Mantén credenciales fuera del agente
Las claves SSH siguen cifradas en la bóveda y nunca entran en el agente ni el terminal.

Solicitar un PTY renuncia a la separación limpia entre la salida estándar y el error estándar remotos. La implementación del servidor OpenSSH duplica el esclavo del PTY en los descriptores 0, 1 y 2. El protocolo tiene un canal de datos ampliado para el error estándar, pero un proceso conectado a un solo terminal ya ha escrito ambos flujos en la misma secuencia de bytes.

Esto rompe un patrón de automatización frecuente:

ssh -T host.example command >result.json 2>diagnostic.log

Sin PTY, el error estándar del programa remoto puede llegar a diagnostic.log mientras el JSON queda en result.json. Con PTY, avisos remotos, solicitudes de contraseña, mensajes de bienvenida, progreso y JSON pueden llegar juntos a result.json; los diagnósticos locales de SSH todavía pueden aparecer en diagnostic.log. La redirección del cliente no puede separar bytes después de que el servidor los haya mezclado.

El procesamiento de salida del terminal también puede convertir un salto de línea en retorno de carro más salto de línea. La entrada puede repetirse, el modo canónico puede esperar una línea completa y los caracteres de control pueden activar funciones del terminal. Son comportamientos correctos para un terminal y corrupciones para un protocolo binario.

Los programas que detectan un terminal suelen añadir colores, barras de progreso, paginadores o avisos. Pueden usar búfer por línea en un terminal y por bloque en una tubería, lo que hace que una ejecución sin PTY parezca detenida aunque siga trabajando. Corrige el búfer en la aplicación cuando sea posible: elige su opción de salida simple, modo sin búfer o registro. Un terminal falso cambia varias variables a la vez y puede ocultar el problema real del búfer.

Si un comando produce datos para máquinas, conserva -T y haz que el programa emita un formato no interactivo. Si necesita de verdad un terminal, trata toda su salida como una transcripción. No analices una transcripción PTY como si fuera una API estable.

El SSH ejecutado por agentes debe fallar sin conversar

Haz que cada clave sensible pregunte
Una clave por llamada puede exigir un clic o Touch ID en cada uso SSH.

Un llamador autónomo no puede controlar con seguridad una conversación de terminal. Un aviso que ayuda a recuperarse a una persona puede hacer que un agente espere, improvise una entrada o clasifique una acción parcial como correcta. El comando SSH debe declarar si permite interacción antes de que aparezcan credenciales, privilegios o estado remoto.

En ejecuciones de agentes, combina la ausencia de PTY con la supresión de avisos en cada capa. La autenticación y verificación del host SSH necesitan una política preparada. La elevación de privilegios debe usar sudo -n. La herramienta remota debe recibir su opción no interactiva, un tiempo límite explícito y entradas mediante archivos o argumentos con nombre, en vez de una conversación. Captura por separado la salida estándar, el error estándar y el estado.

No resuelvas la ausencia de un aviso de contraseña exponiendo una contraseña o clave privada al agente. El material de autenticación y el comportamiento del terminal son asuntos separados. Dar PTY al proceso no reduce lo que pueden hacer unas credenciales robadas, y negar PTY no protege unas credenciales que ya están en su entorno.

Sallyport saca el límite de las credenciales del proceso agente: un agente compatible con MCP solicita una acción SSH mediante el ayudante sin estado sp-ssh, mientras la bóveda cifrada aporta la clave SSH y el diario Activity registra la llamada. El comando sigue necesitando un contrato de PTY intencional porque aislar secretos no decide si el programa remoto espera semántica de terminal.

La aprobación también es distinta de un aviso remoto. Una tarjeta de aprobación local puede autorizar una acción definida antes de ejecutarla; un aviso del terminal remoto aparece dentro de una sesión abierta y puede llegar después de efectos anteriores. Mantén la autorización humana fuera del flujo de bytes remoto para que rechazar tenga un significado claro y los registros identifiquen la acción intentada.

Cuando un agente necesite una herramienta de mantenimiento interactiva, divide el flujo. Deja que prepare un comando o solicitud y entrega después la sesión de terminal en vivo a una persona, o sustituye la herramienta por una operación no interactiva diseñada para automatización. Fingir que un agente es mecanógrafo crea la versión menos comprobable de ambos sistemas.

Elige el modo como parte de la interfaz

El modo correcto depende de la interfaz del programa remoto, no de una regla general sobre si los PTY son buenos o malos. Usa esta lista durante la revisión:

  • Usa -T para JSON, archivos y bytes exactos porque conserva datos transparentes y errores separados.
  • Usa -T con sudo -n para trabajo privilegiado desatendido, de modo que la autenticación falle en vez de esperar.
  • Usa -t cuando una persona vaya a escribir una contraseña de sudo o manejar una interfaz de terminal.
  • Usa -tt desde una tubería o lanzador de agentes solo después de revisar la omisión de la comprobación de TTY local.
  • Envía los trabajos largos a un gestor remoto porque un PTY no ofrece propiedad duradera del proceso.

Registra la elección junto al comando. Las pruebas deben comprobar tipos de descriptor, separación de flujos, cancelación y estado, no solo unas palabras esperadas. Si una actualización de dependencia empieza a exigir un terminal, deja que falle la prueba e investiga el nuevo aviso o rama de detección antes de añadir -t.

Incluye el modo elegido en los registros como metadatos estructurados, en lugar de inferirlo por una salida coloreada o un aviso. Cuando una incidencia atraviese varios hosts, ese único campo permite separar el comportamiento del terminal de fallos de autenticación, red y aplicación antes de volver a ejecutar nada.

La política del servidor puede rechazar PTY mediante la configuración de OpenSSH o una restricción de authorized key. Es otro motivo para no convertirlos en dependencia accidental. Un comando creado para automatización debe seguir funcionando bajo -T; uno interactivo debe fallar con claridad cuando no consiga terminal.

Trata cualquier propuesta de añadir -tt como cambio de interfaz. Vuelve a ejecutar la sonda, redirige ambos flujos locales, envía Ctrl-C, fuerza al comando remoto a devolver un estado distinto de cero y desconecta durante la ejecución. Si no puedes describir el resultado con precisión, el comando no está listo para ejecutarse sin atención.

FAQ

¿Qué hace realmente ssh -t?

Pide al servidor SSH que asigne un PTY y conecte a él la sesión remota. Los programas ven descriptores de terminal, se mezclan los flujos remotos y las reglas de entrada pueden generar señales.

¿Qué diferencia hay entre ssh -t y ssh -tt?

-t fuerza una solicitud de PTY cuando el cliente local tiene terminal. Al repetirlo como -tt, también fuerza la asignación cuando la entrada estándar local no es un terminal, algo común en tuberías y agentes.

¿SSH asigna por defecto un TTY a un comando remoto?

Normalmente, un comando remoto indicado se ejecuta sin PTY. Usa -T para hacer explícita esa elección o -t cuando el comando necesite de verdad un terminal.

¿Por qué sudo falla por SSH sin TTY?

Cuando sudo necesita contraseña, suele leerla del terminal del usuario. Para automatizar, usa sudo -n y una regla sudoers bastante limitada, de modo que el comando falle en vez de preguntar.

¿Es seguro sudo -S en un script SSH?

sudo -S hace responsable al script del transporte de la contraseña y mezcla el secreto con la entrada estándar. Evítalo para agentes y automatización habitual; usa un diseño de autorización que no pregunte.

¿ssh -t carga .bashrc o .profile?

No, la asignación de PTY no selecciona archivos de inicio del shell. Solicita expresamente un shell interactivo o de inicio si hace falta, aunque un entorno y una ruta explícitos dan trabajos más previsibles.

¿Por qué se mezclan stdout y stderr con ssh -t?

OpenSSH conecta los descriptores 1 y 2 al mismo esclavo PTY, por lo que el servidor tiene un solo flujo de bytes de terminal. La redirección posterior del cliente no puede reconstruir los flujos originales.

¿Un PTY cambia el código de salida SSH?

El PTY por sí solo no; OpenSSH sigue devolviendo el estado del comando remoto. Los envoltorios, tuberías, señales y el estado especial 255 del cliente pueden cambiar u ocultar lo que observa el llamador.

¿Por qué Ctrl-C se comporta distinto con y sin ssh -t?

El controlador de un PTY convierte el carácter de interrupción en SIGINT para su grupo de procesos en primer plano. Sin PTY no existe ese grupo remoto, así que cancelar depende del soporte de señales SSH y la estructura de procesos.

¿Deben los agentes de IA usar ssh -tt con comandos que podrían preguntar?

No. Un comando para agentes debe suprimir avisos y fallar con un estado útil; forzar terminal puede convertir un error de configuración en una conversación indefinida y mezclar la salida de diagnóstico.

Sallyport

Sallyport ejecuta llamadas de API y comandos SSH por tu agente de IA. Las claves se quedan en una bóveda local de tu Mac; tú apruebas cada ejecución y cada acción queda en un registro sellado.

© 2026 Sallyport · Código abierto bajo Apache-2.0 · Oleg Sotnikov