在ssh上运行Bash脚本

23

我正试图编写一个Bash脚本,它会SSH连接到一台计算机并创建一个目录。长期目标有点复杂,但现在我从简单开始。然而,尽管很简单,我似乎仍然无法做到这一点。以下是我的代码:

#!/bin/bash
ssh -T tunneluser@111.222.333.444 <<EOI

# Fix "TERM environment variable undefined" error.
TERM=dumb
export TERM

# Store todays date.
NOW=$(date +"%F")
echo $NOW

# Store backup path.
BACKUP="/backup/$NOW"
[ ! -d $BACKUP ] && mkdir -p ${BACKUP}
echo $BACKUP

exit
EOI

它没有明显的错误。然而,回显的$NOW和$BACKUP变量为空,并且/backup目录没有被创建。我该如何修复这个问题?

5个回答

30

本地主机上的shell正在对$NOW和$BACKUP进行变量替换,因为"EOI"没有被转义。请更换为

 ssh tunneluser@111.222.333.444 <<EOI

使用

 ssh tunneluser@111.222.333.444 <<\EOI

谢谢。这个需要的修改最少,而且完美运行。 - Cerin
1
你们两个有没有一个允许在ssh会话中传递变量的例子?例如,如果我在bash脚本中使用了@Cerin之前的块,并且在ssh ...之前声明了REMOTE_PATH=root/stuff/buildpath,那么我能否在我的ssh/heredoc中使用$REMOTE_PATH或类似的东西? - blong
@Brian,使用hbar下面的示例,如果您不转义$REMOTE_PATH,那么它应该被插入到在远程服务器上运行的ssh脚本中。 - Cerin
1
除了反斜杠\,我们还可以使用单引号来包装LimitString,例如EOI,在这种情况下用于在文档中转义特殊字符,例如ssh tunneluser@111.222.333.444 <<'EOI' - Terry Wang

21
变量在本地机器上的脚本中进行评估。您需要用转义符号替换美元符号。
#!/bin/bash
ssh -T tunneluser@111.222.333.444 <<EOI

# Fix "TERM environment variable undefined" error.
TERM=dumb
export TERM

# Store todays date.
NOW=\$(date +"%F")
echo \$NOW

# Store backup path.
BACKUP="/backup/\$NOW"
[ ! -d \$BACKUP ] && mkdir -p \${BACKUP}
echo \$BACKUP

exit
EOI

完美 :) :) 解释...我认为这使得讨论的其余部分变得毫无意义.. - Arindam Paul

6

在发送之前,您的脚本会在本地主机上进行替换。

将您的第一行更改为:

ssh -T tunneluser@111.222.333.444 <<'EOI'

这将导致原始脚本被发送并在远程主机上解释。 如果需要混合执行(例如,如果想在本地主机上执行“date”命令),应该保留ssh行不变,并引用各个命令。
ssh -T tunneluser@111.222.333.444 <<EOI

# Execute the date command on the local machine.  The assignment still
# happens on the remote machine
NOW=$(date +"%F")

# Quote your $ so that the replacement happens on the remote machine
echo \$NOW

你的第二个例子引用了 here-doc 分界符和变量。我认为你只想转义变量,否则加一。 - Dennis Williamson

0

如何通过SSH运行本地脚本

概述:

在不复制脚本文件的情况下通过SSH执行脚本。 您需要一个简单的SSH连接和一个本地脚本。

代码:

#!/bin/sh
print_usage() {
        echo -e "`basename $0` ssh_connexion local_script"
        echo -e "Remote executes local_script on ssh server"
        echo -e "For convinient use, use ssh public key for remote connexion"
        exit 0
}

[ $# -eq "2" ] && [ $1 != "-h" ] && [ $1 != "--help" ] || print_usage

INTERPRETER=$(head -n 1 $2 | sed -e 's/#!//')

cat $2 | grep -v "#" | ssh -t $1 $INTERPRETER

示例:

  • ssh-remote-exec root@server1 myLocalScript.sh #用于Bash
  • ssh-remote-exec root@server1 myLocalScript.py #用于Python
  • ssh-remote-exec root@server1 myLocalScript.pl #用于Perl
  • ssh-remote-exec root@server1 myLocalScript.rb #用于Ruby

逐步解释

此脚本执行以下操作: 1° 获取第一行#!以获取解释器(即:Perl、Python、Ruby、Bash解释器), 2° 在SSH上启动远程解释器, 3° 将所有脚本主体发送到SSH。

本地脚本:

本地脚本必须以#!/path/to/interpreter开头 - #!/bin/sh 用于Bash脚本 - #!/usr/bin/perl 用于Perl脚本 - #!/usr/bin/python 用于Python脚本 - #!/usr/bin/ruby 用于Ruby脚本

此脚本不基于本地脚本扩展名,而是基于#!信息。


1
所有这些-e是什么意思?POSIX并不要求echo -e除了在输出中打印-e之外做任何事情;实际上,做其他任何事情都是明确不合规的,而bash可以在编译时或运行时配置以符合标准的字母,因此echo -e的行为是未定义的,并且差异很大。(如果您的/bin/shdash而不是bash提供,则会获得符合POSIX的行为,因此使用当前脚本编写将在输出中有一堆-e字符串)。 - Charles Duffy
请考虑通过 http://shellcheck.net/ 运行您的代码,并修复它所识别出的引号问题。 - Charles Duffy

-1

尝试:

NOW=`date +"%F"`

2
$()与``是相同的,只不过前者更容易嵌套。这是任何符合POSIX标准的sh都可以处理的事情。 - jamessan
1
@GreenMatt,不仅是“新版本的Bash”,而是所有符合1992年POSIX sh标准的shell。 - Charles Duffy
@GreenMatt,没问题,但是你特别提到了 bash,所以这里我们不讨论 Bourne。我不知道 任何一个 发布的 bash 版本中缺少 $(...);它在 2.0 中肯定存在,并且在从 1.x 迁移时也没有列为更改项,这意味着很可能即使在那时它也不是新功能。 - Charles Duffy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接