【问题标题】:Pass variables to remote script through SSH通过 SSH 将变量传递给远程脚本
【发布时间】:2011-10-08 10:31:05
【问题描述】:

我正在通过 SSH 从本地服务器在远程服务器上运行脚本。该脚本首先使用 SCP 进行复制,然后在传递一些参数时调用,如下所示:

scp /path/to/script server.example.org:/another/path/

ssh server.example.org \
MYVAR1=1 \
MYVAR2=2 \
/another/path/script

这工作正常,在远程服务器上,变量MYVAR1MYVAR2 可以使用它们对应的值。

问题是这些脚本在不断开发中,每次重命名、添加或删除变量时都需要更改 SSH 命令。

我正在寻找一种将所有本地环境变量传递给远程脚本的方法(因为 MYVAR1MYVAR2 实际上是本地环境变量),这将解决 SSH 命令维护问题。

由于MYVAR1=1 \MYVAR1=1 \ 是遵循env 命令输出的行,因此我尝试将它们替换为实际命令,如下所示:

ssh server.example.org \
`env`
/another/path/script

这似乎适用于“简单”env 输出行(例如 SHELL=/bin/bashLOGNAME=sysadmin),但是对于更“复杂”的输出行(例如 LS_COLORS=rs=0:di=01;34:ln=01;[...] 会出现错误,例如 @987654335 @)。我可以通过在运行 SSH 命令(例如unset LS_COLORS,然后是ssh [...])之前取消设置与那些复杂输出行相对应的变量来消除这些错误,但是我发现这个解决方案并不是非常可靠。

问:有人知道如何通过 SSH 将所有本地环境变量传递给远程脚本吗?

PS:本地环境变量不是远程机器so I cannot use this solution上可用的环境变量。

更新解决方案

我结束了使用sedenv 命令输出从VAR=VALUE 格式化为VAR="VALUE"(并将所有行连接到1),这可以防止bash 将某些输出解释为命令并解决我的问题。

ssh server.example.org \
`env | sed 's/\([^=]*\)=\(.*\)/\1="\2"/' | tr '\n' ' '` \
"/another/path/script"

【问题讨论】:

    标签: linux bash shell ubuntu ssh


    【解决方案1】:

    这个解决方案对我很有效。 假设您有一个带有两个参数或两个变量的脚本:

    #!/bin/sh
    echo "local"
    echo "$1"
    echo "$2"
    /usr/bin/ssh root@192.168.1.2 "/path/test.sh \"$1\" \"$2\";"
    

    并在 192.168.1.2 上编写 test.sh 脚本:

    #!/bin/bash
    echo "remote"
    echo "$1"
    echo "$2"
    

    输出将是:

    local
    This is first params
    And this is second
    remote
    This is first params
    And this is second
    

    【讨论】:

      【解决方案2】:

      您应该使用set 而不是env

      来自 bash 手册:

      如果没有选项,每个 shell 变量的名称和值都会以一种格式显示,该格式可以重复用作设置或重置当前设置的变量的输入。

      这将解决您所有的分号和反斜杠问题。

      scp /path/to/script server.example.org:/another/path/
      set > environment
      scp environment server.example.org:/another/path/
      ssh server.example.org "source environment; /another/path/script"
      

      如果您不想发送任何变量,您可以使用以下内容将它们过滤掉:

      set | grep -v "DONT_NEED" > environment
      

      您还可以更新远程系统上的~/.bash_profile 以在您登录时运行环境脚本,这样您就不必显式运行环境脚本:

      ssh server.example.org "/another/path/script"
      

      【讨论】:

        【解决方案3】:

        Perl 的救援:

        #!/usr/bin/perl
        
        use strict;
        use warnings;
        
        use Net::OpenSSH;
        use Getopt::Long;
        
        my $usage = "Usage:\n  $0 --env=FOO --env=BAR ... [user\@]host command args\n\n";
        
        my @envs;
        GetOptions("env=s" => \@envs)
            or die $usage;
        
        my $host = shift @ARGV;
        die $usage unless defined $host and @ARGV;
        
        my $ssh = Net::OpenSSH->new($host);
        $ssh->error and die "Unable to connect to remote host: " . $ssh->error;
        
        my @cmds;
        for my $env (@envs) {
            next unless defined $ENV{$env};
            push @cmds, "export " . $ssh->shell_quote($env) .'='.$ssh->shell_quote($ENV{$env})
        }
        
        my $cmd = join('&&', @cmds, '('. join(' ', @ARGV) .')');
        warn "remote command: $cmd\n";
        $ssh->system($cmd);
        

        如果您的环境变量包含有趣的东西作为引号,它也不会中断。

        【讨论】:

          【解决方案4】:

          问题是; 标记了你的命令的结束。你必须逃脱它们:

          试试这个命令:

          env | sed 's/;/\\;/g'
          

          更新: 我在远程主机上测试了这个命令,它使用这个命令对我有用:

          var1='something;using semicolons;'
          ssh hostname "`env | sed 's/;/\\\\;/g' | sed 's/.*/set &\;/g'` echo \"$var1\""
          

          我双重转义; whit \\\\;,然后我使用另一个sed 替换以set name=value; 的形式输出变量。这样做可以确保在执行命令之前在远程主机上正确设置每个变量。

          【讨论】:

            【解决方案5】:

            我碰巧阅读了与此无关的 sshd_config 手册页并找到了选项 AcceptEnv

            接受环境 指定客户端发送哪些环境变量 将会 复制到会话的环境中(7)。请参阅 SendEnv 中的 ssh_config(5) 了解如何配置客户端。注意 环境 仅协议 2 支持 ronment 传递。 变量是 由名称指定,可能包含通配符 字符*' and?'。多个环境变量可以分开 经过 空格或分布在多个 AcceptEnv 指令中。 是 警告说一些环境变量可以用来 旁路 受限的用户环境。为此,请注意 应该 在使用该指令时采取。默认是不 接受 任何环境变量。

            也许您可以将它与AcceptEnv: * 一起使用?我手边没有带 sshd 的盒子,但试试看吧!

            【讨论】:

            • 我建议使用通用前缀,而不是将其设置为 *(这可能有点风险)
            • @Hasturkun:确实,这通常会更好。但是,据我了解,user359650 似乎希望它是一个非侵入性的完整副本。也许它可以被限制为只对某个用户这样做?
            • 感谢您的建议。我没想到sshd 会提供这样的设施。不幸的是,修改sshd 不是一种选择,因为它适用于所有用户并将另一个工具添加到维护列表中。
            • 这是可以理解的一点。不幸的是,sshd_configMatch 指令不允许 AcceptEnv,否则至少会解决“所有用户”的问题。
            【解决方案6】:

            同时上传环境怎么样?

            scp /path/to/script server.example.org:/another/path/
            env > environment
            scp environment server.example.org:/another/path
            ssh server.example.org "source environment; /another/path/script"
            

            【讨论】:

            • 这个想法是存在的,但是 source environment 仍然因为“复杂”的 env 输出行被解释为命令而中断。
            猜你喜欢
            • 1970-01-01
            • 2023-04-03
            • 2013-03-24
            • 1970-01-01
            • 2012-07-18
            • 1970-01-01
            • 2023-03-11
            • 1970-01-01
            • 2019-12-23
            相关资源
            最近更新 更多