【问题标题】:Running a Bash script over ssh通过 ssh 运行 Bash 脚本
【发布时间】:2011-01-23 09:00:15
【问题描述】:

我正在尝试编写一个 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 目录。我该如何解决这个问题?

【问题讨论】:

    标签: bash scripting ssh


    【解决方案1】:

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

     ssh tunneluser@111.222.333.444 <<EOI
    

     ssh tunneluser@111.222.333.444 <<\EOI
    

    【讨论】:

    • 谢谢。这需要最少的更改,并且效果很好。
    • 你们中的任何一个都有允许将变量传递到 ssh 会话中的示例吗?例如,如果我之前在 bash 脚本中使用了块 @Cerin,并且在声明 REMOTE_PATH=root/stuff/buildpath 之前在 ssh ... 之前,我可以在我的 ssh / heredoc 中使用 $REMOTE_PATH 或类似的东西吗?
    • @Brian,下面使用 hbar 的例子,如果你只是不转义 $REMOTE_PATH,那么它应该被插入到远程服务器上运行的 ssh 脚本中。
    • 除了\之外,我们还可以用单引号包裹LimitString,这里用EOI来转义文档中的特殊字符,例如ssh tunneluser@111.222.333.444 &lt;&lt;'EOI'
    【解决方案2】:

    正在本地计算机上的脚本中评估变量。您需要用转义的美元符号替换美元符号。

    #!/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
    

    【讨论】:

    • 完美 :) :) 解释...我认为这使得其余的讨论毫无用处..
    【解决方案3】:

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

    将第一行更改为:

    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 分隔符和变量。我认为您打算只转义变量。否则 +1
    【解决方案4】:

    如何通过 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 #for Bash
    • ssh-remote-exec root@server1 myLocalScript.py #for Python
    • ssh-remote-exec root@server1 myLocalScript.pl #for Perl
    • ssh-remote-exec root@server1 myLocalScript.rb #for 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 脚本

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

    【讨论】:

    • 所有-es 是怎么回事? POSIX 不需要 echo -e 做任何事情,除了在输出上打印 -e ;事实上,做任何其他事情明显不符合,并且 bash 可以在编译时或运行时配置以符合标准的字母,因此echo -e 的行为是未定义的并且变化很大。 (如果您的/bin/sh 是由dash 而不是bash 提供的,那么您将获得符合POSIX 的行为,因此输出中将包含一堆-e 字符串,而此脚本按原样编写)。
    • 考虑通过shellcheck.net 运行您的代码并修复它识别的引用问题。
    【解决方案5】:

    试试:

    NOW=`date +"%F"`
    

    【讨论】:

    • $() 与 `` 相同,只是前者容易嵌套。这是任何符合 POSIX 标准的 sh 都可以处理的。
    • @GreenMatt,不仅仅是“较新的 bash 版本”,所有符合 1992 POSIX sh 标准的 shell。
    • @GreenMatt,当然,但你是在专门谈论 bash,所以我们在这里不是在谈论 Bourne。而且我不知道 任何 缺少 $(...) 的 bash 发布版本;它肯定存在于 2.0 中,并且也没有被列为对 1.x 的更改,因此推测它即使在那时也不是新的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-01
    • 2016-04-04
    • 2011-12-27
    • 1970-01-01
    • 2014-04-02
    相关资源
    最近更新 更多