Transferindo a variável de ambiente por meio de SSH / aspas no bash / sh / csh / tcsh

3

Eu quero transferir uma variável de ambiente por SSH.

A maneira "correta" é usar SendEnv / ~/.ssh/environment , mas isso requer que o servidor suporte AcceptEnv ou PermitUserEnvironment, o que não acontece no meu caso.

Então, em vez disso, estou pensando em definir a variável no site remoto assim:

FOO=val
export FOO
ssh server export FOO=$FOO'; do_stuff_which_uses_FOO'

Essa parte é fácil. Eu quero uma solução genérica, portanto, não importa o conteúdo de $ FOO, isso funcionará. Por exemplo,

FOO="  '\""
export FOO
QFOO='quote "$FOO"' # quote will return "\ \ \'\\""
export QFOO
ssh server export FOO=$QFOO'; do_stuff_which_uses_FOO'

Isso funciona, não importa se o shell de envio ou recebimento é sh ou bash.

No entanto, também preciso que funcione para csh / tcsh. E eu não vou saber de antemão qual shell a extremidade receptora está rodando. Isso significa que eu tenho que codificar algo que funcionará em / bin / sh e / bin / csh.

Até agora eu consegui trabalhar para sh / bash:

ssh server // followed by the below quoted
eval 'echo $SHELL | grep -E "/(t)?csh" > /dev/null && echo setenv FOO \\ \\ \\\'\\\" || echo export FOO=\\ \\ \\\'\\\";' ; echo "$FOO"

Eu também posso fazê-lo funcionar para csh / tcsh (o usuário csh tem csh como shell de login):

ssh csh@server // followed by the below quoted
eval 'echo $SHELL | grep -E "/(t)?csh" > /dev/null && echo setenv FOO \\ \\ \\\'\\\" || echo export FOO=\\ \\ \\\'\\\";' ; echo "$FOO"

Se $ FOO é * ou? funciona bem com BASH:

ssh server eval\ \'echo\ \$SHELL\ \|\ grep\ -E\ \"/\(t\)\?csh\"\ \>\ /dev/null\ \&\&\ echo\ setenv\ FOO\ \\\\\\*\\;\ \|\|\ echo\ export\ FOO=\\\\\\*\\;\'\;echo\ \"\$FOO\"\ a;

Mas falha com csh:

ssh csh@server eval\ \'echo\ \$SHELL\ \|\ grep\ -E\ \"/\(t\)\?csh\"\ \>\ /dev/null\ \&\&\ echo\ setenv\ FOO\ \\\\\\*\\;\ \|\|\ echo\ export\ FOO=\\\\\\*\\;\'\;echo\ \"\$FOO\"\ a;
No match.
FOO: Undefined variable.

Parece * e? recuse-se a ser citado com.

Para responder a essa pergunta, sua solução deve:

  • conseguir transferir uma variável de ambiente para o servidor remoto
  • não usa SendEnv / AcceptEnv / PermitUserEnvironment
  • trabalhe, não importa se o shell de origem é sh / bash / csh / tcsh
  • trabalhe, não importa se o shell de destino é sh / bash / csh / tcsh
  • funciona, não importa o conteúdo da variável de ambiente. Especificamente, deve pelo menos funcionar para: \ n * espaço '"? <! $ \ E qualquer combinação desses.

Se você puder encontrar uma maneira melhor de transferir a variável do que citá-la, então está tudo bem também.

    
por Ole Tange 02.10.2012 / 17:47

2 respostas

1

Agora tenho um modelo funcional para todos os caracteres, exceto \ n:

sub shell_quote_scalar {
    # Quote the string so shell will not expand any special chars
    # Returns:
    #   string quoted with \ as needed by the shell
    my $a = shift;
    $a =~ s/([
sub shell_quote_scalar {
    # Quote the string so shell will not expand any special chars
    # Returns:
    #   string quoted with \ as needed by the shell
    my $a = shift;
    $a =~ s/([%pre%2-13-2\\#\?\'\(\)\{\}\[\]\*\>\<\~\|\; \"\!\$\&\'2-7])/\$1/g;
    $a =~ s/[\n]/'\n'/g; # filenames with '\n' is quoted using \'
    return $a;
}

sub env_quote {
    my $v = shift;
    $v =~ s/([ \n\&\<\>\(\)\;\'\{\}\t\"\$\'\*4\!\?\~])/\$1/g;
    return $v;
}

my @qcsh = map { my $a=$_; "setenv $a " . env_quote($ENV{$a})  } @vars;
my @qbash = map { my $a=$_; "export $a=" . env_quote($ENV{$a}) } @vars;

$Global::envvar =
    join"",
    (q{echo $SHELL | grep -E "/t?csh" > /dev/null && }
     . join(" && ", @qcsh)
     . q{ || }
     . join(" && ", @qbash)
     .q{;});

print shell_quote_scalar($Global::envvar);
2-13-2\\#\?\'\(\)\{\}\[\]\*\>\<\~\|\; \"\!\$\&\'2-7])/\$1/g; $a =~ s/[\n]/'\n'/g; # filenames with '\n' is quoted using \' return $a; } sub env_quote { my $v = shift; $v =~ s/([ \n\&\<\>\(\)\;\'\{\}\t\"\$\'\*4\!\?\~])/\$1/g; return $v; } my @qcsh = map { my $a=$_; "setenv $a " . env_quote($ENV{$a}) } @vars; my @qbash = map { my $a=$_; "export $a=" . env_quote($ENV{$a}) } @vars; $Global::envvar = join"", (q{echo $SHELL | grep -E "/t?csh" > /dev/null && } . join(" && ", @qcsh) . q{ || } . join(" && ", @qbash) .q{;}); print shell_quote_scalar($Global::envvar);
    
por 15.10.2012 / 13:54
0

Você pode codificar apenas com base64 a variável? A maneira mais fácil de lidar com isso é, provavelmente, simplesmente tratar os dados como binários.

export QFOO='echo $FOO | base64 --wrap=0'
ssh server "export FOO='echo \"$QFOO\" | base64 --decode --wrap=0'; <command>"

Você pode ter que mexer com as citações na linha ssh , mas essa é a essência disso. Isso deve remover detalhes específicos do shell em relação às citações, mas pode introduzir alguns com sub-comandos (não estou muito familiarizado com nada fora de bash )

    
por 02.10.2012 / 18:01