我正在尝试编写一个shell脚本,在远程服务器上创建一些目录,然后使用scp将文件从我的本地机器复制到远程。以下是我目前所了解到的:

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

每当我运行它,我得到这条消息:

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

剧本永远挂着。

我的公钥在服务器上是可信的,我可以在脚本之外运行所有命令。什么好主意吗?


当前回答

我不知道挂起的原因是什么,但是将命令重定向(或管道)到交互式ssh通常会出现问题。使用command-to-run-as- last-argument样式并在ssh命令行上传递脚本会更健壮:

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'

(所有这些都包含在一个以'分隔的多行命令行参数中)。

伪终端消息是因为您的-t要求ssh尝试使它在远程机器上运行的环境看起来像在那里运行的程序的实际终端。您的ssh客户端拒绝这样做,因为它自己的标准输入不是终端,所以它没有办法将特殊的终端api从远程机器传递到您在本地端的实际终端。

你想用-t实现什么呢?

其他回答

在看了很多这样的答案之后,我想分享一下我的解决方案。我只是在heredoc之前添加了/bin/bash,它不再给出错误了。

用这个:

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

而不是这个(给出错误):

ssh user@machine <<'ENDSSH'
   hostname
ENDSSH

或者用这个:

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

而不是这个(给出错误):

ssh user@machine < run-command.sh

额外的:

如果你仍然需要一个远程交互式提示,例如,如果你正在远程运行的脚本提示你输入密码或其他信息,因为前面的解决方案不允许你输入提示。

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

如果你还想把整个会话记录在一个文件logfile.log中:

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

我添加这个答案是因为它解决了与我遇到的相同错误消息相关的问题。

问题:我在Windows下安装了cygwin,并得到这个错误:伪终端将不会被分配,因为stdin不是终端

解决方案:原来我没有安装openssh客户端程序和实用程序。正因为如此,cygwin使用的是ssh的Windows实现,而不是cygwin版本。解决方案是安装openssh cygwin包。

我不知道挂起的原因是什么,但是将命令重定向(或管道)到交互式ssh通常会出现问题。使用command-to-run-as- last-argument样式并在ssh命令行上传递脚本会更健壮:

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'

(所有这些都包含在一个以'分隔的多行命令行参数中)。

伪终端消息是因为您的-t要求ssh尝试使它在远程机器上运行的环境看起来像在那里运行的程序的实际终端。您的ssh客户端拒绝这样做,因为它自己的标准输入不是终端,所以它没有办法将特殊的终端api从远程机器传递到您在本地端的实际终端。

你想用-t实现什么呢?

还有manual中的选项-T

禁用伪tty分配

尝试ssh -t -t(或简称ssh -tt)强制伪tty分配,即使stdin不是终端。

请参见:终止bash脚本执行的SSH会话

从ssh manpage:

-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.