Ich versuche, ein Shell-Skript zu schreiben, das einige Verzeichnisse auf einem Remote-Server erstellt und dann mit scp Dateien von meinem lokalen Computer auf den Remote-Computer kopiert. Folgendes habe ich bisher:
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
Immer wenn ich es starte, erhalte ich folgende Meldung:
Pseudo-terminal will not be allocated because stdin is not a terminal.
Und das Drehbuch hängt einfach für immer.
Mein öffentlicher Schlüssel ist auf dem Server vertrauenswürdig und ich kann alle Befehle außerhalb des Skripts problemlos ausführen. Irgendwelche Ideen?
ssh user@server /bin/bash <<EOT…
/bin/bash
explizite Angabe ist eine Möglichkeit, das Problem zu vermeiden.Antworten:
Versuchen Sie
ssh -t -t
(oderssh -tt
kurz), die Pseudo-Tty-Zuweisung zu erzwingen, auch wenn stdin kein Terminal ist.Siehe auch: Beenden der SSH-Sitzung, die vom Bash-Skript ausgeführt wird
Von der SSH-Manpage:
quelle
ssh -t -t
und nichtssh -tt
? Gibt es einen Unterschied, den ich nicht kenne?Inappropriate IOCtl for device
-tt
und-t -t
sind gleichwertig; Das separate oder zusammengesteckte Festlegen von Argumenten ist eine Frage des persönlichen Stils / der persönlichen Präferenz, und wenn es darauf ankommt, gibt es gültige Argumente dafür. aber wirklich, es ist nur eine persönliche Präferenz.Auch mit Option
-T
aus dem Handbuchquelle
-tt
Option erscheint am besten für diejenigen von uns, die tatsächlich ein TTY wollen und die Fehlermeldung des OP erhalten. Diese-T
Antwort ist besser, wenn Sie das TTY nicht benötigen.Per zanco Antwort , ich sofern Sie nicht einen Remote - Befehl zu
ssh
, da , wie die Shell die Befehlszeile analysiert. Um dieses Problem zu lösen, ändern Sie die Syntax Ihresssh
Befehlsaufrufs so, dass der Remote-Befehl aus einer syntaktisch korrekten mehrzeiligen Zeichenfolge besteht.Es gibt verschiedene Syntaxen, die verwendet werden können. Da Befehle beispielsweise in
bash
undsh
und wahrscheinlich auch in andere Shells weitergeleitet werden können, besteht die einfachste Lösung darin, denssh
Shell-Aufruf einfach mit Heredocs zu kombinieren :Beachten Sie, dass das Ausführen der obigen Schritte ohne
/bin/bash
die Warnung führtPseudo-terminal will not be allocated because stdin is not a terminal
. Beachten Sie auch, dass diesEOT
von einfachen Anführungszeichen umgeben ist, sodassbash
der Heredoc als Nowdoc erkannt wird und die Interpolation lokaler Variablen deaktiviert wird , sodass der Befehlstext unverändert übergeben wirdssh
.Wenn Sie ein Fan von Pfeifen sind, können Sie die oben genannten Punkte wie folgt umschreiben:
Die gleiche Einschränkung
/bin/bash
gilt für die oben genannten.Ein anderer gültiger Ansatz besteht darin, den mehrzeiligen Remote-Befehl als einzelne Zeichenfolge zu übergeben, wobei mehrere Ebenen
bash
variabler Interpolation wie folgt verwendet werden:Die obige Lösung behebt dieses Problem auf folgende Weise:
ssh user@server
wird von bash analysiert und alsssh
Befehl interpretiert , gefolgt von einem Argumentuser@server
, das an denssh
Befehl übergeben werden soll"
beginnt eine interpolierte Zeichenfolge, die nach Abschluss ein Argument enthält, das an denssh
Befehl übergeben werden soll. In diesem Fall wird dies als Remotebefehl interpretiertssh
, als den ausgeführt werden solluser@server
$(
Startet die Ausführung eines Befehls, wobei die Ausgabe von der umgebenden interpolierten Zeichenfolge erfasst wirdcat
ist ein Befehl zum Ausgeben des Inhalts einer beliebigen Datei. Die Ausgabe voncat
wird an die erfasste interpolierte Zeichenfolge zurückgegeben<<
beginnt ein Bash Heredoc'EOT'
Gibt an, dass der Name des Heredocs EOT ist. Die einfachen Anführungszeichen'
um EOT geben an, dass der Heredoc als Nowdoc analysiert werden soll. Dies ist eine spezielle Form des Heredoc, bei der der Inhalt nicht durch Bash interpoliert, sondern im Literalformat weitergegeben wirdAlle Inhalte, die zwischen
<<'EOT'
und<newline>EOT<newline>
jetzt an die nowdoc-Ausgabe angehängt werdenEOT
Beendet den NowDOC, wodurch eine temporäre NowDOC-Datei erstellt und an den aufrufendencat
Befehl zurückgegeben wird.cat
gibt den nowdoc aus und gibt die Ausgabe an die erfasste interpolierte Zeichenfolge zurück)
schließt den auszuführenden Befehl ab"
schließt die erfasste interpolierte Zeichenfolge ab. Der Inhalt der interpolierten Zeichenfolge wirdssh
als einzelnes Befehlszeilenargument zurückgegeben, dasssh
als Remote-Befehl zur Ausführung interpretiert wirduser@server
Wenn Sie die Verwendung externer Tools wie z. B. vermeiden
cat
möchten und zwei Anweisungen anstelle einer Anweisung verwendenread
möchten , verwenden Sie die integrierte Funktion mit einem Heredoc, um den SSH-Befehl zu generieren:quelle
cat
Lösung besteht auch darin, dass sie in einer einzigen (wenn auch zusammengesetzten) Anweisung ausgeführt wird und nicht dazu führt, dass temporäre Variablen die Shell-Umgebung verschmutzen.Ich füge diese Antwort hinzu, weil sie ein verwandtes Problem gelöst hat, das ich mit derselben Fehlermeldung hatte.
Problem : Ich hatte cygwin unter Windows installiert und bekam diesen Fehler:
Pseudo-terminal will not be allocated because stdin is not a terminal
Lösung : Es stellte sich heraus, dass ich das OpenSh-Client-Programm und die Dienstprogramme nicht installiert hatte. Aus diesem Grund verwendete cygwin die Windows-Implementierung von ssh, nicht die cygwin-Version. Die Lösung bestand darin, das Paket openssh cygwin zu installieren.
quelle
$ which ssh/cygdrive/c/Program Files (x86)/Git/bin/ssh
openssh
dies zu installieren, kann der Weg für Windows sein: superuser.com/a/301026/260710Die Warnmeldung
Pseudo-terminal will not be allocated because stdin is not a terminal.
ist darauf zurückzuführen, dass kein Befehl angegeben ist,ssh
während stdin von einem Here-Dokument umgeleitet wird. Aufgrund des Fehlens eines angegebenen Befehls als Argument wirdssh
zunächst eine interaktive Anmeldesitzung erwartet (die die Zuweisung eines Pty auf dem Remote-Host erfordern würde), muss dann jedoch erkennen, dass sein lokaler Standard kein Tty / Pty ist. Umssh
das stdin von einem Here-Dokument umzuleiten, muss normalerweise ein Befehl (z. B./bin/sh
) als Argument angegeben werden. In diesemssh
Fall wird standardmäßig keine pty auf dem Remote-Host zugewiesen.Da keine Befehle ausgeführt werden müssen
ssh
, für die ein tty / pty (wievim
odertop
) erforderlich ist-t
,ssh
ist der Wechsel zu überflüssig. Verwenden Sie einfachssh -T user@server <<EOT ...
oderssh user@server /bin/bash <<EOT ...
und die Warnung verschwindet.Wenn
<<EOF
keine Escape- oder einfach in Anführungszeichen gesetzten (dh<<\EOT
oder<<'EOT'
) Variablen im hier gezeigten Dokument von der lokalen Shell erweitert werden, bevor sie ausgeführt wirdssh ...
. Dies hat zur Folge, dass die Variablen im Dokument hier leer bleiben, da sie nur in der Remote-Shell definiert sind.Wenn
$REL_DIR
also sowohl für die lokale Shell zugänglich als auch für die Remote-Shell definiert werden soll,$REL_DIR
muss dies vor demssh
Befehl außerhalb des hier angegebenen Dokuments definiert werden ( Version 1 unten). oder, wenn<<\EOT
oder<<'EOT'
verwendet wird, kann die Ausgabe desssh
Befehls zugewiesen werden,REL_DIR
wenn die einzige Ausgabe desssh
Befehls an stdout vonecho "$REL_DIR"
innerhalb des hier mit Escapezeichen / einfachen Anführungszeichen versehenen Dokuments ( Version 2 unten) generiert wird .Eine dritte Möglichkeit wäre, das hier gezeigte Dokument in einer Variablen zu speichern und diese Variable dann als Befehlsargument an
ssh -t user@server "$heredoc"
( Version 3 unten) zu übergeben.Und zu guter Letzt wäre es keine schlechte Idee zu überprüfen, ob die Verzeichnisse auf dem Remote-Host erfolgreich erstellt wurden (siehe: Überprüfen Sie, ob die Datei auf dem Remote-Host mit ssh vorhanden ist ).
quelle
Alle relevanten Informationen sind in den vorhandenen Antworten enthalten, aber lassen Sie mich eine pragmatische Zusammenfassung versuchen :
tl; dr:
Übergeben Sie die auszuführenden Befehle mit einem Befehlszeilenargument :
ssh jdoe@server '...'
'...'
Zeichenfolgen können mehrere Zeilen umfassen, sodass Sie Ihren Code auch ohne Verwendung eines Here-Dokuments lesbar halten können:ssh jdoe@server ' ... '
Übergeben Sie die Befehle NICHT über stdin , wie dies bei Verwendung eines Here-Dokuments der Fall ist :
ssh jdoe@server <<'EOF' # Do NOT do this ... EOF
Das Übergeben der Befehle als Argument funktioniert unverändert und:
exit
am Ende Ihrer Befehle keine Anweisung , da die Sitzung automatisch beendet wird, nachdem die Befehle verarbeitet wurden.Kurz gesagt: Das Übergeben von Befehlen über stdin ist ein Mechanismus, der im Widerspruch zum
ssh
Design steht und Probleme verursacht, die dann umgangen werden müssen.Lesen Sie weiter, wenn Sie mehr wissen möchten.
Optionale Hintergrundinformationen:
ssh
Der Mechanismus zum Akzeptieren von Befehlen zur Ausführung auf dem Zielserver ist ein Befehlszeilenargument : Der letzte Operand (Nichtoptionsargument) akzeptiert eine Zeichenfolge, die einen oder mehrere Shell-Befehle enthält.Standardmäßig werden diese Befehle unbeaufsichtigt in einer nicht interaktiven Shell ohne Verwendung eines (Pseudo-) Terminals ausgeführt (Option
-T
ist impliziert), und die Sitzung wird automatisch beendet, wenn der letzte Befehl die Verarbeitung beendet hat.Für den Fall, dass Ihre Befehle eine Benutzerinteraktion erfordern , z. B. das Antworten auf eine interaktive Eingabeaufforderung, können Sie explizit die Erstellung eines Pty (Pseudo-Tty) anfordern , eines Pseudo-Terminals, das die Interaktion mit der Remote-Sitzung mithilfe der
-t
Option ermöglicht. z.B:ssh -t jdoe@server 'read -p "Enter something: "; echo "Entered: [$REPLY]"'
Beachten Sie, dass die interaktive
read
Eingabeaufforderung nur mit einem Pty korrekt funktioniert, sodass die-t
Option benötigt wird.Die Verwendung eines Pty hat einen bemerkenswerten Nebeneffekt: stdout und stderr werden kombiniert und beide über stdout gemeldet ; Mit anderen Worten: Sie verlieren die Unterscheidung zwischen regulärer und Fehlerausgabe. z.B:
ssh jdoe@server 'echo out; echo err >&2' # OK - stdout and stderr separate
ssh -t jdoe@server 'echo out; echo err >&2' # !! stdout + stderr -> stdout
ssh
Wenn dieses Argument nicht vorhanden ist, wird eine interaktive Shell erstellt - auch wenn Sie Befehle über stdin senden. Hier beginnt das Problem:Bei einer interaktiven Shell wird
ssh
normalerweise standardmäßig ein pty (Pseudo-Terminal) zugewiesen, es sei denn, sein Standard ist nicht mit einem (realen) Terminal verbunden.Das Senden von Befehlen über stdin bedeutet, dass
ssh
stdin nicht mehr mit einem Terminal verbunden ist, sodass kein pty erstellt wird, undssh
warnt Sie entsprechend :Pseudo-terminal will not be allocated because stdin is not a terminal.
Auch die
-t
Option, deren ausdrücklicher Zweck ist auf Anfrage Schaffung eines pty, ist nicht genug , um in diesem Fall : Sie werden die gleiche Warnung.Etwas seltsamerweise müssen Sie dann die Option verdoppeln
-t
, um die Erstellung eines Pty zu erzwingen:ssh -t -t ...
oderssh -tt ...
zeigt, dass Sie es wirklich ernst meinen .Vielleicht liegt der Grund dafür, dass dieser sehr bewusste Schritt erforderlich ist, darin, dass die Dinge möglicherweise nicht wie erwartet funktionieren . Unter macOS 10.12 funktioniert beispielsweise das scheinbare Äquivalent des obigen Befehls, der die Befehle über stdin bereitstellt und verwendet
-tt
, nicht ordnungsgemäß. Die Sitzung bleibt hängen, nachdem auf dieread
Eingabeaufforderung reagiert wurde :ssh -tt jdoe@server <<<'read -p "Enter something: "; echo "Entered: [$REPLY]"'
In dem unwahrscheinlichen Fall, dass die Befehle, die Sie als Argument übergeben möchten, die Befehlszeile für Ihr System zu lang machen (wenn sich ihre Länge nähert
getconf ARG_MAX
- siehe diesen Artikel ), sollten Sie den Code zuerst in Form eines Skripts auf das ferne System kopieren ( Verwenden Sie z. B.scp
) und senden Sie dann einen Befehl, um dieses Skript auszuführen.Verwenden Sie zur Not
-T
die Befehle und geben Sie sie über stdin mit einem abschließendenexit
Befehl ein. Beachten Sie jedoch, dass die Verwendung-tt
anstelle von-T
möglicherweise nicht funktioniert , wenn Sie auch interaktive Funktionen benötigen .quelle
Ich weiß nicht, woher der Hang kommt, aber das Umleiten (oder Weiterleiten) von Befehlen in ein interaktives SSH ist im Allgemeinen ein Rezept für Probleme. Es ist robuster, den Befehl zum Ausführen als letztes Argument zu verwenden und das Skript in der ssh-Befehlszeile zu übergeben:
(Alles in einem riesigen,
'
mehrzeiligen Befehlszeilenargument).Die Pseudo-Terminal-Nachricht ist darauf zurückzuführen, dass Sie
-t
ssh auffordern, zu versuchen, die auf dem Remotecomputer ausgeführte Umgebung für die dort ausgeführten Programme wie ein tatsächliches Terminal aussehen zu lassen. Ihr SSH-Client lehnt dies ab, da seine eigene Standardeingabe kein Terminal ist und er daher keine Möglichkeit hat, die speziellen Terminal-APIs vom Remote-Computer an Ihr eigentliches Terminal am lokalen Ende weiterzuleiten.Was wollten Sie überhaupt erreichen
-t
?quelle
-T
stattdessen die Option .Nachdem ich viele dieser Antworten gelesen hatte, dachte ich, ich würde meine resultierende Lösung teilen. Alles, was ich hinzugefügt habe, ist
/bin/bash
vor dem Heredoc und es gibt keinen Fehler mehr.Benutze das:
Stattdessen (gibt Fehler):
Oder benutze dies:
Stattdessen (gibt Fehler):
ZUSÄTZLICH :
Wenn Sie weiterhin eine interaktive Remote-Eingabeaufforderung wünschen, z. B. wenn das Skript, das Sie remote ausführen, Sie zur Eingabe eines Kennworts oder anderer Informationen auffordert, da Sie in den vorherigen Lösungen die Eingabeaufforderungen nicht eingeben können.
Und wenn Sie auch die gesamte Sitzung in einer Datei protokollieren möchten
logfile.log
:quelle
Ich hatte unter Windows den gleichen Fehler mit emacs 24.5.1, um über / ssh: user @ host eine Verbindung zu einigen Unternehmensservern herzustellen. Was mein Problem gelöst hat, war, die Variable "tramp-default-method" auf "plink" zu setzen und jedes Mal, wenn ich eine Verbindung zu einem Server herstelle, das ssh-Protokoll zu deaktivieren. Sie müssen PuTTYs plink.exe installiert haben, damit dies funktioniert.
Lösung
quelle
ssh -t foobar @ localhost yourscript.pl
quelle
-t
auch, aber in ihrem spezifischen Szenario ist das nicht genug, was die Frage zunächst veranlasste.