Estou tentando escrever um script de shell que cria alguns diretórios em um servidor remoto e, em seguida, usa o scp para copiar arquivos da minha máquina local para o controle remoto. Aqui está o que eu tenho até agora:
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
Sempre que o executo, recebo esta mensagem:
Pseudo-terminal will not be allocated because stdin is not a terminal.
E o script trava para sempre.
Minha chave pública é confiável no servidor e posso executar todos os comandos fora do script. Alguma ideia?
ssh user@server /bin/bash <<EOT…
/bin/bash
explicitamente é uma maneira de evitar o problema.Respostas:
Tente
ssh -t -t
(oussh -tt
abrevie) forçar a alocação de pseudo-tty, mesmo que stdin não seja um terminal.Consulte também: Terminando a sessão SSH executada pelo script bash
Na página de manual do ssh:
fonte
ssh -t -t
e nãossh -tt
? Existe uma diferença que eu não estou ciente?Inappropriate IOCtl for device
-tt
e-t -t
são equivalentes; especificar args separadamente ou agrupados torna-se uma questão de estilo / preferência pessoal e, quando se trata disso, há argumentos válidos para fazê-lo de qualquer maneira. mas, na verdade, é apenas preferência pessoal.Também com opção
-T
de manualfonte
-tt
opção parece melhor para aqueles que realmente querem um TTY e estão recebendo a mensagem de erro do OP. Essa-T
resposta é melhor se você não precisar do TTY.De acordo com a resposta do zanco , você não está fornecendo um comando remoto
ssh
, considerando como o shell analisa a linha de comando. Para resolver esse problema, altere a sintaxe da suassh
chamada de comando para que o comando remoto seja composto por uma cadeia de linhas multilinhas sintaticamente correta.Há uma variedade de sintaxes que podem ser usadas. Por exemplo, como os comandos podem ser canalizados
bash
esh
, e provavelmente outros shells, a solução mais simples é combinar assh
chamada de shell com os heredocs:Observe que a execução acima sem
/bin/bash
resultará no avisoPseudo-terminal will not be allocated because stdin is not a terminal
. Observe também queEOT
está entre aspas simples, de modo quebash
reconhece o heredoc como um nowoc , desativando a interpolação de variável local para que o texto do comando seja passado como estássh
.Se você é um fã de pipes, pode reescrever o que foi dito acima, da seguinte maneira:
A mesma ressalva
/bin/bash
se aplica ao acima.Outra abordagem válida é passar o comando remoto com várias linhas como uma única sequência, usando várias camadas de
bash
interpolação de variáveis da seguinte maneira:A solução acima corrige esse problema da seguinte maneira:
ssh user@server
é analisado pelo bash e é interpretado como ossh
comando, seguido por um argumentouser@server
a ser passado aossh
comando"
inicia uma cadeia de caracteres interpolada que, quando concluída, compreenderá um argumento a ser passado para ossh
comando, que neste caso será interpretadossh
como o comando remoto a ser executado comouser@server
$(
inicia um comando a ser executado, com a saída sendo capturada pela sequência interpolada circundantecat
é um comando para gerar o conteúdo de qualquer arquivo a seguir. A saída decat
será passada de volta para a sequência interpolada de captura<<
começa um heredoc da festança'EOT'
especifica que o nome do heredoc é EOT. As aspas simples ao'
redor do EOT especificam que o heredoc deve ser analisado como um nowdoc , que é uma forma especial de heredoc na qual o conteúdo não é interpolado pelo bash, mas transmitido no formato literalQualquer conteúdo encontrado entre
<<'EOT'
e<newline>EOT<newline>
será anexado à saída nowdocEOT
finaliza o nowdoc, resultando em um arquivo temporário do nowdoc sendo criado e transmitido de volta aocat
comando de chamada .cat
gera o nowdoc e passa a saída de volta para a sequência interpolada de captura)
conclui o comando a ser executado"
conclui a captura da cadeia interpolada. O conteúdo da cadeia de caracteres interpolada será passado de volta parassh
um único argumento de linha de comando, quessh
interpretará como o comando remoto para executar comouser@server
Se você precisar evitar o uso de ferramentas externas como
cat
, e não se importar de ter duas instruções em vez de uma, use oread
built-in com um heredoc para gerar o comando SSH:fonte
cat
solução é que ela é realizada em uma única instrução (embora composta) e não resulta em variáveis temporárias poluindo o ambiente do shell.Estou adicionando esta resposta porque resolveu um problema relacionado que eu estava tendo com a mesma mensagem de erro.
Problema : Instalei o cygwin no Windows e estava recebendo este erro:
Pseudo-terminal will not be allocated because stdin is not a terminal
Resolução : Acontece que eu tinha não instalado o programa e os utilitários do openssh. Por esse motivo, o cygwin estava usando a implementação do ssh no Windows, não a versão do cygwin. A solução foi instalar o pacote openssh cygwin.
fonte
$ which ssh/cygdrive/c/Program Files (x86)/Git/bin/ssh
openssh
lo pode ser o caminho a seguir para o Windows: superuser.com/a/301026/260710A mensagem de aviso
Pseudo-terminal will not be allocated because stdin is not a terminal.
deve-se ao fato de nenhum comando ser especificadossh
enquanto o stdin é redirecionado de um documento aqui. Devido à falta de um comando especificado, o argumentossh
primeiro espera uma sessão de logon interativa (o que exigiria a alocação de um pty no host remoto), mas é necessário perceber que seu stdin local não é tty / pty. O redirecionamento dessh
stdin de um documento aqui normalmente exige que um comando (como/bin/sh
) seja especificado como argumento parassh
- e, nesse caso, nenhum pty será alocado no host remoto por padrão.Como não há comandos a serem executados via
ssh
que exijam a presença de um tty / pty (comovim
outop
) o-t
comutador parassh
é supérfluo. Apenas usessh -T user@server <<EOT ...
oussh user@server /bin/bash <<EOT ...
e o aviso desaparecerá.Se
<<EOF
não for escapado ou as variáveis de aspas simples (<<\EOT
ou seja<<'EOT'
) dentro do documento aqui serão expandidas pelo shell local antes de serem executadasssh ...
. O efeito é que as variáveis contidas no documento aqui permanecerão vazias porque são definidas apenas no shell remoto.Portanto, se
$REL_DIR
deve ser acessível pelo shell local e definido no shell remoto,$REL_DIR
deve ser definido fora do documento aqui antes dossh
comando ( versão 1 abaixo); ou, se<<\EOT
ou<<'EOT'
é usado, a saída dossh
comando pode ser atribuído aREL_DIR
se a única saída dossh
comando para stdout é genererated porecho "$REL_DIR"
dentro do / documento único citado aqui (escapou versão 2 abaixo).Uma terceira opção seria armazenar o documento aqui em uma variável e depois passá-la como argumento de comando para
ssh -t user@server "$heredoc"
( versão 3 abaixo).E, por último, mas não menos importante, não seria uma má idéia verificar se os diretórios no host remoto foram criados com êxito (consulte: verifique se o arquivo existe no host remoto com ssh ).
fonte
Todas as informações relevantes estão nas respostas existentes, mas deixe-me tentar um resumo pragmático :
tl; dr:
Passe os comandos para execução usando um argumento de linha de comando :
ssh jdoe@server '...'
'...'
strings podem abranger várias linhas, para que você possa manter seu código legível mesmo sem o uso de um documento aqui:ssh jdoe@server ' ... '
NÃO passe os comandos via stdin , como é o caso quando você usa um documento aqui :
ssh jdoe@server <<'EOF' # Do NOT do this ... EOF
Passar os comandos como argumento funciona como está e:
exit
declaração no final de seus comandos, porque a sessão será encerrada automaticamente após o processamento dos comandos.Resumindo: passar comandos via stdin é um mecanismo que está em desacordo com
ssh
o design e causa problemas que devem ser contornados.Continue lendo, se você quiser saber mais.
Informações complementares opcionais:
ssh
O mecanismo de aceitação de comandos para execução no servidor de destino é um argumento da linha de comandos : o operando final (argumento não opcional) aceita uma sequência que contém um ou mais comandos shell.Por padrão, esses comandos são executados sem supervisão, em um shell não interativo , sem o uso de um terminal (pseudo) (opção
-T
implícita), e a sessão termina automaticamente quando o último comando termina o processamento.Caso seus comandos exijam interação do usuário , como responder a um prompt interativo, você pode solicitar explicitamente a criação de um pty (pseudo-tty) , um pseudo terminal, que permita interagir com a sessão remota, usando o
-t
opção; por exemplo:ssh -t jdoe@server 'read -p "Enter something: "; echo "Entered: [$REPLY]"'
Observe que o interativo
read
prompt funciona apenas corretamente com um pty, portanto, a-t
opção é necessária.O uso de um pty tem um efeito colateral notável: stdout e stderr são combinados e ambos relatados via stdout ; em outras palavras: você perde a distinção entre saída regular e saída de erro; por exemplo:
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
Na ausência deste argumento,
ssh
cria um shell interativo - inclusive quando você envia comandos via stdin , que é onde o problema começa:Para um shell interativo ,
ssh
normalmente aloca um pty (pseudo-terminal) por padrão, exceto se seu stdin não estiver conectado a um terminal (real).Enviar comandos via stdin significa que
ssh
o stdin não está mais conectado a um terminal, portanto, nenhum pty é criado essh
avisa você de acordo :Pseudo-terminal will not be allocated because stdin is not a terminal.
Mesmo a
-t
opção, cujo objetivo expresso é solicitar a criação de um pty, não é suficiente neste caso : você receberá o mesmo aviso.Um pouco curiosamente, você deve dobrar a
-t
opção de forçar a criação de um pty:ssh -t -t ...
oussh -tt ...
mostra que você realmente, realmente quer dizer isso .Talvez a justificativa para exigir essa etapa muito deliberada seja que as coisas podem não funcionar como o esperado . Por exemplo, no macOS 10.12, o aparente equivalente do comando acima, fornecendo os comandos via stdin e usando
-tt
, não funciona corretamente; a sessão fica presa após responder aoread
prompt:ssh -tt jdoe@server <<<'read -p "Enter something: "; echo "Entered: [$REPLY]"'
No caso improvável de que os comandos que você deseja passar como argumento tornem a linha de comando muito longa para o seu sistema (se o comprimento se aproximar
getconf ARG_MAX
- consulte este artigo ), considere primeiro copiar o código para o sistema remoto na forma de um script ( usando, por exemplo,scp
) e envie um comando para executar esse script.Em uma pitada, use
-T
e forneça os comandos via stdin , com umexit
comando à direita , mas observe que se você também precisar de recursos interativos, o uso-tt
no lugar de-T
pode não funcionar.fonte
Não sei de onde vem o travamento, mas redirecionar (ou canalizar) comandos para um ssh interativo geralmente é uma receita para problemas. É mais robusto usar o estilo de comando para executar como último argumento e passar o script na linha de comando ssh:
(Tudo em um gigante
'
único argumento de linha de comando multilinha e delimitado).A mensagem do pseudo-terminal é por causa da sua,
-t
que pede ao ssh para tentar fazer com que o ambiente em que é executado na máquina remota pareça um terminal real para os programas que são executados lá. Seu cliente ssh está se recusando a fazer isso porque sua própria entrada padrão não é um terminal, portanto, não há como passar as APIs especiais do terminal da máquina remota para o seu terminal real na extremidade local.O que você estava tentando alcançar de
-t
qualquer maneira?fonte
-T
.Depois de ler muitas dessas respostas, pensei em compartilhar minha solução resultante. Tudo o que eu adicionei é
/bin/bash
antes do heredoc e ele não dá mais o erro.Usa isto:
Em vez disso (dá erro):
Ou use isto:
Em vez disso (dá erro):
EXTRA :
Se você ainda deseja um prompt interativo remoto, por exemplo, se o script que você está executando remotamente solicitar uma senha ou outras informações, porque as soluções anteriores não permitirão que você digite os prompts.
E se você também deseja registrar a sessão inteira em um arquivo
logfile.log
:fonte
Eu estava tendo o mesmo erro no Windows usando o emacs 24.5.1 para conectar-se a alguns servidores da empresa por meio de / ssh: user @ host. O que resolveu meu problema foi definir a variável "tramp-default-method" como "plink" e sempre que eu me conecto a um servidor, omito o protocolo ssh. Você precisa ter o plink.exe do PuTTY instalado para que isso funcione.
Solução
fonte
ssh -t foobar @ localhost seu script.pl
fonte
-t
também usa , mas em seu cenário específico isso não é suficiente, o que levou a questão a começar.