El pseudoterminal no se asignará porque la entrada estándar no es un terminal

Resuelto Matthew asked hace 13 años • 9 respuestas

Estoy intentando escribir un script de shell que cree algunos directorios en un servidor remoto y luego use scp para copiar archivos desde mi máquina local al control remoto. Esto es lo que tengo hasta ahora:

ssh -t user@server<<EOT
DEP_ROOT='/home/matthewr/releases'
datestamp=$(date +%Y%m%d%H%M%S)
REL_DIR=$DEP_ROOT"/"$datestamp
if [ ! -d "$DEP_ROOT" ]; then
    echo "creating the root directory"
    mkdir $DEP_ROOT
fi
mkdir $REL_DIR
exit
EOT

scp ./dir1 user@server:$REL_DIR
scp ./dir2 user@server:$REL_DIR

Cada vez que lo ejecuto me sale este mensaje:

Pseudo-terminal will not be allocated because stdin is not a terminal.

Y el guión simplemente se cuelga para siempre.

Mi clave pública es confiable en el servidor y puedo ejecutar todos los comandos fuera del script sin problemas. ¿Algunas ideas?

Matthew avatar Aug 19 '11 05:08 Matthew
Aceptado

Intente ssh -t -t(o ssh -ttpara abreviar) forzar la asignación de pseudo-tty incluso si la entrada estándar no es una terminal.

Ver también: Terminar la sesión SSH ejecutada por el script bash

Desde la página de manual de ssh:

-T      Disable pseudo-tty allocation.

-t      Force pseudo-tty allocation.  This can be used to execute arbitrary 
        screen-based programs on a remote machine, which can be very useful,
        e.g. when implementing menu services.  Multiple -t options force tty
        allocation, even if ssh has no local tty.
carok avatar Aug 19 '2011 13:08 carok

También con opción -Tde manual.

Deshabilitar la asignación de pseudo-tty

Emil Bojda avatar Jan 19 '2014 19:01 Emil Bojda

Según la respuesta de Zanco , no está proporcionando un comando remoto ssh, dada la forma en que el Shell analiza la línea de comando. Para resolver este problema, cambie la sintaxis de su sshinvocación de comando para que el comando remoto esté compuesto por una cadena de varias líneas sintácticamente correcta.

Hay una variedad de sintaxis que se pueden utilizar. Por ejemplo, dado que los comandos se pueden canalizar a bashand shy probablemente también a otros shells, la solución más sencilla es simplemente combinar sshla invocación del shell con heredocs:

ssh user@server /bin/bash <<'EOT'
echo "These commands will be run on: $( uname -a )"
echo "They are executed by: $( whoami )"
EOT

Tenga en cuenta que ejecutar lo anterior sin /bin/bash generará la advertencia Pseudo-terminal will not be allocated because stdin is not a terminal. También tenga en cuenta que EOTestá entre comillas simples, por lo que bashreconoce el heredoc como un nowdoc , desactivando la interpolación de variables locales para que el texto del comando se pase tal cual a ssh.

Si eres fanático de las pipas, puedes reescribir lo anterior de la siguiente manera:

cat <<'EOT' | ssh user@server /bin/bash
echo "These commands will be run on: $( uname -a )"
echo "They are executed by: $( whoami )"
EOT

La misma advertencia /bin/bashse aplica a lo anterior.

Otro enfoque válido es pasar el comando remoto de varias líneas como una sola cadena, utilizando múltiples capas de bashinterpolación variable de la siguiente manera:

ssh user@server "$( cat <<'EOT'
echo "These commands will be run on: $( uname -a )"
echo "They are executed by: $( whoami )"
EOT
)"

La solución anterior soluciona este problema de la siguiente manera:

  1. ssh user@serveres analizado por bash y se interpreta como el sshcomando, seguido de un argumento user@serverque se pasará al sshcomando

  2. "comienza una cadena interpolada, que cuando se complete, comprenderá un argumento que se pasará al sshcomando, que en este caso será interpretado como sshel comando remoto a ejecutar comouser@server

  3. $(comienza a ejecutar un comando, y la salida es capturada por la cadena interpolada circundante

  4. cates un comando para generar el contenido de cualquier archivo que siga. La salida de catse devolverá a la cadena interpolada de captura.

  5. <<comienza un bash heredoc

  6. 'EOT'especifica que el nombre del heredoc es EOT. Las comillas simples 'que rodean a EOT especifican que el heredoc debe analizarse como un nowdoc , que es una forma especial de heredoc en la que bash no interpola el contenido, sino que se transmite en formato literal.

  7. Cualquier contenido que se encuentre entre <<'EOT'y <newline>EOT<newline>se agregará a la salida de nowdoc

  8. EOTfinaliza el nowdoc, lo que da como resultado la creación de un archivo temporal nowdoc y su devolución al catcomando de llamada. catgenera el nowdoc y pasa la salida a la cadena interpolada de captura

  9. )concluye el comando a ejecutar

  10. "concluye la captura de la cadena interpolada. El contenido de la cadena interpolada se devolverá sshcomo un único argumento de línea de comando, que sshse interpretará como el comando remoto para ejecutar comouser@server

Si necesita evitar el uso de herramientas externas como caty no le importa tener dos declaraciones en lugar de una, use el readheredoc integrado para generar el comando SSH:

IFS='' read -r -d '' SSH_COMMAND <<'EOT'
echo "These commands will be run on: $( uname -a )"
echo "They are executed by: $( whoami )"
EOT

ssh user@server "${SSH_COMMAND}"
Dejay Clayton avatar Feb 13 '2014 17:02 Dejay Clayton