J'essaie d'écrire un script shell qui crée des répertoires sur un serveur distant et utilise ensuite scp pour copier des fichiers de ma machine locale sur la télécommande. Voici ce que j'ai jusqu'à présent:
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
Chaque fois que je l'exécute, je reçois ce message:
Pseudo-terminal will not be allocated because stdin is not a terminal.
Et le script se bloque pour toujours.
Ma clé publique est approuvée sur le serveur et je peux très bien exécuter toutes les commandes en dehors du script. Des idées?
ssh user@server /bin/bash <<EOT…
/bin/bash
explicitement est un moyen d'éviter le problème.Réponses:
Essayez
ssh -t -t
(oussh -tt
pour faire court) de forcer l'allocation de pseudo-tty même si stdin n'est pas un terminal.Voir aussi: Terminer la session SSH exécutée par le script bash
Depuis la page de manuel de ssh:
la source
ssh -t -t
et nonssh -tt
? Y a-t-il une différence que je ne connais pas?Inappropriate IOCtl for device
-tt
et-t -t
sont équivalents; la spécification d'arguments séparément ou de smooshed ensemble devient une question de style / préférence personnelle, et quand il s'agit, il y a des arguments valables pour le faire de toute façon. mais vraiment, c'est juste une préférence personnelle.Également avec option
-T
du manuella source
-tt
option apparaît mieux pour ceux d'entre nous qui veulent réellement un ATS et reçoivent le message d'erreur de l'OP. Cette-T
réponse est meilleure si vous n'avez pas besoin du téléscripteur.Selon la réponse de Zanco , vous ne fournissez pas de commande à distance
ssh
, étant donné la façon dont le shell analyse la ligne de commande. Pour résoudre ce problème, modifiez la syntaxe de votressh
appel de commande afin que la commande distante soit composée d'une chaîne multi-lignes syntaxiquement correcte.Il existe une variété de syntaxes qui peuvent être utilisées. Par exemple, puisque les commandes peuvent être canalisées dans
bash
etsh
, et probablement aussi d'autres shells, la solution la plus simple est de simplement combiner l'ssh
invocation du shell avec heredocs:Notez que l'exécution de ce qui précède sans
/bin/bash
entraînera l'avertissementPseudo-terminal will not be allocated because stdin is not a terminal
. Notez également qu'ilEOT
est entouré de guillemets simples, ce quibash
reconnaît l'heredoc comme un nowdoc , désactivant l'interpolation de variable locale afin que le texte de la commande soit transmis tel quel àssh
.Si vous êtes un fan de tuyaux, vous pouvez réécrire ce qui suit comme suit:
La même mise en garde à propos de
/bin/bash
s'applique à ce qui précède.Une autre approche valide consiste à passer la commande à distance multi-ligne en une seule chaîne, en utilisant plusieurs couches d'
bash
interpolation variable comme suit:La solution ci-dessus résout ce problème de la manière suivante:
ssh user@server
est analysé par bash, et est interprété comme étant lassh
commande, suivi d'un argumentuser@server
à passer à lassh
commande"
commence une chaîne interpolée qui, une fois terminée, comprendra un argument à passer à lassh
commande, qui dans ce cas sera interprété parssh
comme étant la commande distante à exécuter commeuser@server
$(
commence une commande à exécuter, la sortie étant capturée par la chaîne interpolée environnantecat
est une commande pour afficher le contenu du fichier suivant. La sortie decat
sera retransmise dans la chaîne interpolée de capture<<
commence un hérédoc bash'EOT'
spécifie que le nom de l'hérédoc est EOT. Les guillemets simples'
entourant EOT spécifient que l'heredoc doit être analysé en tant que nowdoc , qui est une forme spéciale d'heredoc dans laquelle le contenu n'est pas interpolé par bash, mais plutôt transmis au format littéralTout contenu rencontré entre
<<'EOT'
et<newline>EOT<newline>
sera ajouté à la sortie nowdocEOT
termine nowdoc, ce qui entraîne la création et la retransmission d'un fichier temporaire nowdoc à lacat
commande appelante .cat
sort le nowdoc et retransmet la sortie à la chaîne interpolée de capture)
conclut la commande à exécuter"
conclut la capture de la chaîne interpolée. Le contenu de la chaîne interpolée sera retransmis enssh
tant qu'argument de ligne de commande unique, quissh
sera interprété comme la commande distante à exécuter commeuser@server
Si vous devez éviter d'utiliser des outils externes comme
cat
, et cela ne vous dérange pas d'avoir deux instructions au lieu d'une, utilisez leread
intégré avec un hérédoc pour générer la commande SSH:la source
cat
solution est qu'elle est accomplie dans une seule instruction (bien que composée) et n'entraîne pas de variables temporaires polluant l'environnement shell.J'ajoute cette réponse car elle a résolu un problème connexe que j'avais avec le même message d'erreur.
Problème : j'avais installé cygwin sous Windows et j'obtenais cette erreur:
Pseudo-terminal will not be allocated because stdin is not a terminal
Résolution : il s'avère que je n'avais pas installé le programme client et les utilitaires openssh. À cause de cela, cygwin utilisait l'implémentation Windows de ssh, pas la version cygwin. La solution consistait à installer le package openssh cygwin.
la source
$ which ssh/cygdrive/c/Program Files (x86)/Git/bin/ssh
openssh
cela peut être la voie à suivre pour Windows: superuser.com/a/301026/260710Le message d'avertissement
Pseudo-terminal will not be allocated because stdin is not a terminal.
est dû au fait qu'aucune commande n'est spécifiée pendantssh
que stdin est redirigé à partir d'un document ici. En raison de l'absence d'une commande spécifiée, un argumentssh
attend d'abord une session de connexion interactive (qui nécessiterait l'allocation d'un pty sur l'hôte distant), mais doit ensuite se rendre compte que son stdin local n'est pas tty / pty. La redirectionssh
de stdin à partir d'un document ici nécessite normalement une commande (telle que/bin/sh
) à spécifier comme argumentssh
- et dans ce cas, aucun pty ne sera alloué sur l'hôte distant par défaut.Puisqu'il n'y a pas de commandes à exécuter via
ssh
qui nécessitent la présence d'un tty / pty (commevim
outop
), le-t
commutateur versssh
est superflu. Utilisez simplementssh -T user@server <<EOT ...
oussh user@server /bin/bash <<EOT ...
et l'avertissement disparaîtra.If
<<EOF
n'est pas échappé ou les variables entre guillemets simples (ie<<\EOT
ou<<'EOT'
) à l'intérieur du document ici seront développées par le shell local avant son exécutionssh ...
. L'effet est que les variables à l'intérieur du document ici resteront vides car elles sont définies uniquement dans le shell distant.Donc, si
$REL_DIR
doit être à la fois accessible par le shell local et défini dans le shell distant,$REL_DIR
doit être défini en dehors du document here avant lassh
commande ( version 1 ci-dessous); ou, si<<\EOT
ou<<'EOT'
est utilisé, la sortie de lassh
commande peut être affectée àREL_DIR
si la seule sortie de lassh
commande vers stdout est générée par l'echo "$REL_DIR"
intérieur du document d'échappement / guillemets simples ici ( version 2 ci-dessous).Une troisième option serait de stocker le document ici dans une variable, puis de passer cette variable comme argument de commande à
ssh -t user@server "$heredoc"
( version 3 ci-dessous).Et, last but not least, ce ne serait pas une mauvaise idée de vérifier si les répertoires sur l'hôte distant ont été créés avec succès (voir: vérifier si le fichier existe sur l'hôte distant avec ssh ).
la source
Toutes les informations pertinentes se trouvent dans les réponses existantes, mais permettez-moi de tenter un résumé pragmatique :
tl; dr:
PASSEZ les commandes à exécuter à l'aide d'un argument de ligne de commande :
ssh jdoe@server '...'
'...'
les chaînes peuvent s'étendre sur plusieurs lignes, vous pouvez donc garder votre code lisible même sans l'utilisation d'un document ici:ssh jdoe@server ' ... '
Ne passez PAS les commandes via stdin , comme c'est le cas lorsque vous utilisez un document ici :
ssh jdoe@server <<'EOF' # Do NOT do this ... EOF
Passer les commandes comme argument fonctionne tel quel et:
exit
instruction à la fin de vos commandes, car la session se fermera automatiquement après le traitement des commandes.En bref: passer des commandes via stdin est un mécanisme qui est en contradiction avec
ssh
la conception de et provoque des problèmes qui doivent ensuite être contournés.Continuez à lire, si vous voulez en savoir plus.
Informations générales facultatives:
ssh
Le mécanisme d'acceptation des commandes à exécuter sur le serveur cible est un argument de ligne de commande : l'opérande final (argument sans option) accepte une chaîne contenant une ou plusieurs commandes shell.Par défaut, ces commandes s'exécutent sans surveillance, dans un shell non interactif , sans l'utilisation d'un (pseudo) terminal (option
-T
implicite), et la session se termine automatiquement lorsque la dernière commande termine le traitement.Dans le cas où vos commandes nécessitent une interaction de l'utilisateur , comme répondre à une invite interactive, vous pouvez explicitement demander la création d'un pty (pseudo-tty) , un pseudo terminal, qui permet d'interagir avec la session distante, en utilisant l'
-t
option; par exemple:ssh -t jdoe@server 'read -p "Enter something: "; echo "Entered: [$REPLY]"'
Notez que l'
read
invite interactive ne fonctionne correctement qu'avec un pty, donc l'-t
option est nécessaire.L'utilisation d'un pty a un effet secondaire notable: stdout et stderr sont combinés et tous deux signalés via stdout ; en d'autres termes: vous perdez la distinction entre sortie régulière et sortie d'erreur; par exemple:
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
En l'absence de cet argument,
ssh
crée un shell interactif - y compris lorsque vous envoyez des commandes via stdin , où commence le problème:Pour un shell interactif ,
ssh
alloue normalement un pty (pseudo-terminal) par défaut, sauf si son stdin n'est pas connecté à un (vrai) terminal.L'envoi de commandes via stdin signifie que
ssh
stdin n'est plus connecté à un terminal, donc aucun pty n'est créé, et vousssh
avertit en conséquence :Pseudo-terminal will not be allocated because stdin is not a terminal.
Même l'
-t
option, dont le but exprès est de demander la création d'un pty, ne suffit pas dans ce cas : vous obtiendrez le même avertissement.Curieusement, vous devez ensuite doubler l'
-t
option pour forcer la création d'un pty:ssh -t -t ...
oussh -tt ...
montrer que vous le pensez vraiment, vraiment .La raison pour laquelle cette étape très délibérée est peut-être justifiée est que les choses peuvent ne pas fonctionner comme prévu . Par exemple, sur macOS 10.12, l'équivalent apparent de la commande ci-dessus, fournissant les commandes via stdin et utilisant
-tt
, ne fonctionne pas correctement; la session se bloque après avoir répondu à l'read
invite:ssh -tt jdoe@server <<<'read -p "Enter something: "; echo "Entered: [$REPLY]"'
Dans le cas peu probable où les commandes que vous souhaitez passer en argument rendent la ligne de commande trop longue pour votre système (si sa longueur approche
getconf ARG_MAX
- voir cet article ), envisagez d'abord de copier le code sur le système distant sous la forme d'un script ( en utilisant, par exemple,scp
), puis envoyez une commande pour exécuter ce script.Dans un pincement, utilisez
-T
et fournissez les commandes via stdin , avec uneexit
commande de fin , mais notez que si vous avez également besoin de fonctionnalités interactives, l'utilisation-tt
au lieu de-T
peut ne pas fonctionner.la source
Je ne sais pas d'où vient le blocage, mais rediriger (ou canaliser) les commandes vers un ssh interactif est en général une recette pour les problèmes. Il est plus robuste d'utiliser le style de commande pour exécuter en tant que dernier argument et de passer le script sur la ligne de commande ssh:
(Tout en un géant
'
argument de ligne de commande multiligne délimité ).Le message pseudo-terminal est dû à votre message
-t
qui demande à ssh d'essayer de faire en sorte que l'environnement qu'il exécute sur la machine distante ressemble à un terminal réel pour les programmes qui s'y exécutent. Votre client ssh refuse de le faire car sa propre entrée standard n'est pas un terminal, il n'a donc aucun moyen de transmettre les API de terminal spéciales de la machine distante à votre terminal réel à l'extrémité locale.Qu'essayiez-vous de faire de
-t
toute façon?la source
-T
plutôt l' option .Après avoir lu beaucoup de ces réponses, j'ai pensé partager ma solution résultante. Tout ce que j'ai ajouté est
/bin/bash
avant l'hérédoc et cela ne donne plus l'erreur.Utilisez ceci:
Au lieu de cela (donne une erreur):
Ou utilisez ceci:
Au lieu de cela (donne une erreur):
EXTRA :
Si vous voulez toujours une invite interactive à distance, par exemple si le script que vous exécutez à distance vous demande un mot de passe ou d'autres informations, car les solutions précédentes ne vous permettront pas de taper les invites.
Et si vous souhaitez également enregistrer toute la session dans un fichier
logfile.log
:la source
J'avais la même erreur sous Windows en utilisant emacs 24.5.1 pour me connecter à certains serveurs de l'entreprise via / ssh: user @ host. Ce qui a résolu mon problème était de définir la variable "tramp-default-method" sur "plink" et chaque fois que je me connecte à un serveur, j'oublie le protocole ssh. Vous devez avoir installé plink.exe de PuTTY pour que cela fonctionne.
Solution
la source
ssh -t foobar @ localhost yourscript.pl
la source
-t
également, mais dans leur scénario spécifique, cela ne suffit pas, ce qui a amené la question à commencer.