489 Stimmen

Das Pseudoterminal wird nicht zugewiesen, da stdin kein Terminal ist.

Ich versuche, ein Shell-Skript zu schreiben, das einige Verzeichnisse auf einem entfernten Server erstellt und dann scp verwendet, um Dateien von meinem lokalen Rechner auf den entfernten zu kopieren. Hier ist, was ich bis jetzt habe:

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

Jedes Mal, wenn ich es ausführe, erhalte ich diese Meldung:

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

Und das Skript bleibt einfach ewig hängen.

Mein öffentlicher Schlüssel ist auf dem Server vertrauenswürdig, und ich kann alle Befehle außerhalb des Skripts problemlos ausführen. Irgendeine Idee?

43voto

zanco Punkte 466

Die Warnmeldung Pseudo-terminal will not be allocated because stdin is not a terminal. ist auf die Tatsache zurückzuführen, dass kein Befehl für ssh während stdin von einem Dokument hierher umgeleitet wird. In Ermangelung eines angegebenen Befehls als Argument ssh erwartet zunächst eine interaktive Anmeldesitzung (was die Zuweisung eines pty auf dem entfernten Rechner erfordern würde), muss dann aber feststellen, dass seine lokale stdin kein tty/pty ist. Umleitung von ssh stdin aus einem Dokument hier zu lesen, erfordert normalerweise einen Befehl (wie /bin/sh ), die als Argument für ssh - und in einem solchen Fall wird auf dem entfernten Rechner standardmäßig kein pty zugewiesen.

Da es keine Befehle gibt, die über ssh die das Vorhandensein eines tty/pty erfordern (wie z.B. vim o top ) die -t umschalten ssh ist überflüssig. Verwenden Sie einfach ssh -T user@server <<EOT ... o ssh user@server /bin/bash <<EOT ... und die Warnung wird verschwinden.

Si <<EOF nicht escaped oder in Anführungszeichen gesetzt ist (d. h. <<\EOT o <<'EOT' ) werden die Variablen in diesem Dokument von der lokalen Shell expandiert, bevor sie ausgeführt werden ssh ... . Dies hat zur Folge, dass die Variablen in diesem Dokument leer bleiben, da sie nur in der entfernten Shell definiert sind.

Also, wenn $REL_DIR sollte sowohl von der lokalen Shell zugänglich als auch in der entfernten Shell definiert sein, $REL_DIR muss außerhalb des vorliegenden Dokuments definiert werden, bevor die ssh Befehl ( Version 1 unten); oder, wenn <<\EOT o <<'EOT' verwendet wird, wird die Ausgabe der ssh Befehl kann zugewiesen werden REL_DIR wenn die einzige Ausgabe des ssh Befehl auf stdout wird generiert durch echo "$REL_DIR" innerhalb des escaped/single-quoted here Dokuments ( Version 2 unten).

Eine dritte Möglichkeit wäre, das Dokument hier in einer Variablen zu speichern und diese Variable dann als Befehlsargument an ssh -t user@server "$heredoc" ( Version 3 unten).

Und zu guter Letzt wäre es keine schlechte Idee, zu überprüfen, ob die Verzeichnisse auf dem entfernten Rechner erfolgreich erstellt wurden (siehe: prüfen, ob die Datei auf dem entfernten Rechner mit ssh existiert ).

# version 1

unset DEP_ROOT REL_DIR
DEP_ROOT='/tmp'
datestamp=$(date +%Y%m%d%H%M%S)
REL_DIR="${DEP_ROOT}/${datestamp}"

ssh localhost /bin/bash <<EOF
if [ ! -d "$DEP_ROOT" ] && [ ! -e "$DEP_ROOT" ]; then
   echo "creating the root directory" 1>&2
   mkdir "$DEP_ROOT"
fi
mkdir "$REL_DIR"
#echo "$REL_DIR"
exit
EOF

scp -r ./dir1 user@server:"$REL_DIR"
scp -r ./dir2 user@server:"$REL_DIR"

# version 2

REL_DIR="$(
ssh localhost /bin/bash <<\EOF
DEP_ROOT='/tmp'
datestamp=$(date +%Y%m%d%H%M%S)
REL_DIR="${DEP_ROOT}/${datestamp}"
if [ ! -d "$DEP_ROOT" ] && [ ! -e "$DEP_ROOT" ]; then
   echo "creating the root directory" 1>&2
   mkdir "$DEP_ROOT"
fi
mkdir "$REL_DIR"
echo "$REL_DIR"
exit
EOF
)"

scp -r ./dir1 user@server:"$REL_DIR"
scp -r ./dir2 user@server:"$REL_DIR"

# version 3

heredoc="$(cat <<'EOF'
# -onlcr: prevent the terminal from converting bare line feeds to carriage return/line feed pairs
stty -echo -onlcr
DEP_ROOT='/tmp'
datestamp="$(date +%Y%m%d%H%M%S)"
REL_DIR="${DEP_ROOT}/${datestamp}"
if [ ! -d "$DEP_ROOT" ] && [ ! -e "$DEP_ROOT" ]; then
   echo "creating the root directory" 1>&2
   mkdir "$DEP_ROOT"
fi
mkdir "$REL_DIR"
echo "$REL_DIR"
stty echo onlcr
exit
EOF
)"

REL_DIR="$(ssh -t localhost "$heredoc")"

scp -r ./dir1 user@server:"$REL_DIR"
scp -r ./dir2 user@server:"$REL_DIR"

26voto

Ich weiß nicht, woher der Fehler kommt, aber das Umleiten (oder Einfügen) von Befehlen in eine interaktive ssh ist im Allgemeinen ein Rezept für Probleme. Es ist robuster, den Stil "Befehl zum Ausführen als letztes Argument" zu verwenden und das Skript in der ssh-Befehlszeile zu übergeben:

ssh user@server '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'

(Alles in einem einzigen riesigen ' -begrenztes mehrzeiliges Befehlszeilenargument).

Die Pseudo-Endnachricht ist auf Ihre -t die ssh auffordert, die Umgebung, die es auf dem entfernten Rechner ausführt, für die Programme, die dort laufen, wie ein echtes Terminal aussehen zu lassen. Ihr ssh-Client weigert sich, dies zu tun, weil sein eigene Die Standardeingabe ist kein Terminal, so dass es keine Möglichkeit gibt, die speziellen Terminal-APIs von der entfernten Maschine an Ihr tatsächliches Terminal auf der lokalen Seite weiterzugeben.

Was wollten Sie erreichen mit -t sowieso?

7voto

Wadih M. Punkte 11645

Nachdem ich viele dieser Antworten gelesen habe, dachte ich, ich würde meine Lösung mit Ihnen teilen. Alles, was ich hinzugefügt habe, ist /bin/bash vor dem Heredoc und der Fehler tritt nicht mehr auf.

Verwenden Sie dies:

ssh user@machine /bin/bash <<'ENDSSH'
   hostname
ENDSSH

Stattdessen (gibt Fehler):

ssh user@machine <<'ENDSSH'
   hostname
ENDSSH

Oder verwenden Sie dies:

ssh user@machine /bin/bash < run-command.sh

Stattdessen (gibt Fehler):

ssh user@machine < run-command.sh

EXTRA :

Wenn Sie dennoch eine interaktive Eingabeaufforderung wünschen, z. B. wenn das Skript, das Sie aus der Ferne ausführen, Sie zur Eingabe eines Kennworts oder anderer Informationen auffordert, weil die bisherigen Lösungen Ihnen nicht erlauben, die Eingabeaufforderungen einzugeben.

ssh -t user@machine "$(<run-command.sh)"

Und wenn Sie auch die gesamte Sitzung in einer Datei protokollieren wollen logfile.log :

ssh -t user@machine "$(<run-command.sh)" | tee -a logfile.log

0voto

Miguel Rentes Punkte 992

Ich hatte den gleichen Fehler unter Windows, als ich emacs 24.5.1 benutzte, um mich mit einigen Firmenservern über /ssh:user@host zu verbinden. Mein Problem wurde gelöst, indem ich die "tramp-default-method"-Variable auf "plink" gesetzt habe und jedes Mal, wenn ich mich mit einem Server verbinde, das ssh-Protokoll ausschalte. Sie müssen die plink.exe von PuTTY installiert haben, damit dies funktioniert.

Solution

  1. M-x customize-variable (und dann Enter drücken)
  2. tramp-default-method (und drücken Sie dann erneut die Eingabetaste)
  3. Geben Sie in das Textfeld "plink" ein, dann "Apply" und speichern Sie den Puffer.
  4. Wenn ich versuche, auf einen entfernten Server zuzugreifen, verwende ich jetzt C-x-f /user@host: und gebe dann das Passwort ein. Die Verbindung wird nun unter Emacs auf Windows korrekt zu meinem entfernten Server hergestellt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X