我正在尝试编写一个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.
剧本永远挂着。
我的公钥在服务器上是可信的,我可以在脚本之外运行所有命令。什么好主意吗?
The warning message Pseudo-terminal will not be allocated because stdin is not a terminal. is due to the fact that no command is specified for ssh while stdin is redirected from a here document.
Due to the lack of a specified command as an argument ssh first expects an interactive login session (which would require the allocation of a pty on the remote host) but then has to realize that its local stdin is no tty/pty. Redirecting ssh's stdin from a here document normally requires a command (such as /bin/sh) to be specified as an argument to ssh - and in such a case no pty will be allocated on the remote host by default.
由于通过ssh执行的命令不需要tty/pty(如vim或top),所以切换到ssh的-t是多余的。
只需使用ssh -T user@server <<EOT…或ssh user@server /bin/bash <<EOT…警告就会消失。
如果<<EOF没有转义或单引号(即<<\EOT或<<'EOT'),这里文档中的变量将在执行ssh ....之前由本地shell展开结果是,这里文档中的变量将保持为空,因为它们仅在远程shell中定义。
因此,如果$REL_DIR既可以被本地shell访问,又可以在远程shell中定义,那么$REL_DIR必须在ssh命令(下面的版本1)之前在here文档之外定义;或者,如果使用<<\EOT或<<'EOT',如果ssh命令对stdout的唯一输出是由转义/单引号here文档中的echo "$REL_DIR"生成的,则ssh命令的输出可以分配给REL_DIR(下面的版本2)。
第三种方法是将here文档存储在一个变量中,然后将该变量作为命令参数传递给ssh -t user@server "$heredoc"(下面是第3版)。
最后但并非最不重要的是,检查远程主机上的目录是否已成功创建(参见:使用ssh检查远程主机上是否存在文件)也不是一个坏主意。
# version 1
unset DEP_ROOT REL_DIR
DEP_ROOT='/tmp'
datestamp=$(date +%Y%m%d%H%M%S)
REL_DIR="${DEP_ROOT}/${datestamp}"
ssh localhost /bin/bash <<EOF
if [ ! -d "$DEP_ROOT" ] && [ ! -e "$DEP_ROOT" ]; then
echo "creating the root directory" 1>&2
mkdir "$DEP_ROOT"
fi
mkdir "$REL_DIR"
#echo "$REL_DIR"
exit
EOF
scp -r ./dir1 user@server:"$REL_DIR"
scp -r ./dir2 user@server:"$REL_DIR"
# version 2
REL_DIR="$(
ssh localhost /bin/bash <<\EOF
DEP_ROOT='/tmp'
datestamp=$(date +%Y%m%d%H%M%S)
REL_DIR="${DEP_ROOT}/${datestamp}"
if [ ! -d "$DEP_ROOT" ] && [ ! -e "$DEP_ROOT" ]; then
echo "creating the root directory" 1>&2
mkdir "$DEP_ROOT"
fi
mkdir "$REL_DIR"
echo "$REL_DIR"
exit
EOF
)"
scp -r ./dir1 user@server:"$REL_DIR"
scp -r ./dir2 user@server:"$REL_DIR"
# version 3
heredoc="$(cat <<'EOF'
# -onlcr: prevent the terminal from converting bare line feeds to carriage return/line feed pairs
stty -echo -onlcr
DEP_ROOT='/tmp'
datestamp="$(date +%Y%m%d%H%M%S)"
REL_DIR="${DEP_ROOT}/${datestamp}"
if [ ! -d "$DEP_ROOT" ] && [ ! -e "$DEP_ROOT" ]; then
echo "creating the root directory" 1>&2
mkdir "$DEP_ROOT"
fi
mkdir "$REL_DIR"
echo "$REL_DIR"
stty echo onlcr
exit
EOF
)"
REL_DIR="$(ssh -t localhost "$heredoc")"
scp -r ./dir1 user@server:"$REL_DIR"
scp -r ./dir2 user@server:"$REL_DIR"