终端将不会被分配,因为stdin不是终端

我正在尝试编写一个在远程服务器上创建一些目录的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 -t -t (或简称ssh -tt )来强制伪tty分配,即使stdin不是终端。

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

从ssh手册页:

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

还有手动选项-T

禁用伪tty分配


Per zanco的回答是,你没有提供远程命令给ssh ,因为shell解析命令行的方式。 要解决此问题,请更改ssh命令调用的语法,以便远程命令由语法正确的多行字符串组成。

有多种可以使用的语法。 例如,由于可以将命令传送到bashsh ,也可能是其他shell,最简单的解决方案是将ssh shell调用与heredocs结合使用:

ssh user@server /bin/bash <<'EOT'
echo "These commands will be run on: $( uname -a )"
echo "They are executed by: $( whoami )"
EOT

请注意,执行上面没有/bin/bash将导致警告Pseudo-terminal will not be allocated because stdin is not a terminal 。 还要注意, EOT被单引号括起来,所以bash将heredoc识别为nowdoc,关闭局部变量插值,以便命令文本将原样传递给ssh

如果你是管道迷,你可以重写上面的内容,如下所示:

cat <<'EOT' | ssh user@server /bin/bash
echo "These commands will be run on: $( uname -a )"
echo "They are executed by: $( whoami )"
EOT

关于/bin/bash警告适用于上述情况。

另一种有效的方法是将多行远程命令作为单个字符串传递,使用多层bash变量插值,如下所示:

ssh user@server "$( cat <<'EOT'
echo "These commands will be run on: $( uname -a )"
echo "They are executed by: $( whoami )"
EOT
)"

上述解决方案以下列方式解决了此问题:

  • ssh user@server被bash解析,并被解释为ssh命令,随后是一个参数user@server以传递给ssh命令

  • "开始一个插入的字符串,当完成时,它将包含一个参数传递给ssh命令,在这种情况下,它将被ssh解释为要作为user@server执行的远程命令

  • $(开始一个要执行的命令,输出被周围的内插字符串捕获

  • cat是一个输出任何文件内容的命令。 cat的输出将被传回到捕获的内插字符串中

  • <<开始一场狂欢heredoc

  • 'EOT'指定heredoc的名称是EOT。 单引号'周围的EOT指定的定界符应被解析为一个nowdoc,这是定界符的一种特殊形式,其内容不要被bash的插值,但在文字格式,而传递

  • <<'EOT'<newline>EOT<newline>之间遇到的任何内容将被附加到nowdoc输出

  • EOT终止nowdoc,导致创建一个nowdoc临时文件并将其传递回调用cat命令。 cat输出nowdoc并将输出传递回捕获内插字符串

  • )结束要执行的命令

  • "结束捕获内插字符串,内插字符串的内容将作为单个命令行参数传递回ssh ,该ssh将解释为要作为user@server执行的远程命令

  • 如果您需要避免使用cat类的外部工具,并且不介意使用两个语句而不是一个语句,请使用带有heredoc的内置read来生成SSH命令:

    IFS='' read -r -d '' SSH_COMMAND <<'EOT'
    echo "These commands will be run on: $( uname -a )"
    echo "They are executed by: $( whoami )"
    EOT
    
    ssh user@server "${SSH_COMMAND}"
    
    链接地址: http://www.djcxy.com/p/17501.html

    上一篇: terminal will not be allocated because stdin is not a terminal

    下一篇: Weird behaviour of cp command