Übertragen der Umgebungsvariablen über SSH / quoting in bash / sh / csh / tcsh

2683
Ole Tange

Ich möchte eine Umgebungsvariable über SSH übertragen.

Die "richtige" Methode ist die Verwendung von SendEnv /. Dies ~/.ssh/environmentsetzt jedoch voraus, dass der Server AcceptEnv oder PermitUserEnvironment unterstützt, was in meinem Fall jedoch nicht der Fall ist.

Stattdessen denke ich, die Variable auf dem entfernten Standort wie folgt festzulegen:

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

Dieser Teil ist einfach. Ich möchte eine generische Lösung, also unabhängig vom Inhalt von $ FOO wird es funktionieren. Z.B

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

Dies funktioniert unabhängig davon, ob die sendende oder empfangende Shell sh oder bash ist.

Ich brauche es aber auch für csh / tcsh. Und ich werde nicht im Voraus wissen, welche Shell das empfangende Ende läuft. Das heißt, ich muss etwas programmieren, das sowohl in / bin / sh als auch in / bin / csh funktioniert.

Bisher ist es mir gelungen, es für sh / bash zum Laufen zu bringen:

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

Ich kann es auch für csh / tcsh verwenden (der Benutzer cshhat csh als Login-Shell):

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" 

Wenn $ FOO * ist oder? es funktioniert gut mit BASH:

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

Mit csh schlägt es fehl:

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. 

Es scheint * und? sich weigern, mit zitiert zu werden.

Um diese Frage zu beantworten, sollte Ihre Lösung:

  • eine Umgebungsvariable auf den Remote-Server übertragen können
  • Verwenden Sie SendEnv / AcceptEnv / PermitUserEnvironment nicht
  • Egal ob die Quellenshell sh / bash / csh / tcsh ist
  • Egal ob die Zielshell sh / bash / csh / tcsh ist
  • unabhängig vom Inhalt der Umgebungsvariablen arbeiten. Insbesondere sollte es zumindest für Folgendes funktionieren: \ n * Leerzeichen '"? <>! $ \ Und eine beliebige Kombination davon.

Wenn Sie einen besseren Weg finden können, die Variable zu übertragen, als sie anzugeben, ist dies ebenfalls in Ordnung.

3
Es klingt, als würden wir deine Hausaufgaben machen. Warum können Sie die Optionen ssh SendEnv oder AcceptEnv nicht verwenden? Dafür werden sie entworfen. UtahJarhead vor 11 Jahren 0
Es ist für --env in GNU Parallel zu verwenden. GNU Parallel wird von geschätzten 25000 Benutzern verwendet. Viele dieser Benutzer haben keinen Root-Zugriff auf die von ihnen verwendeten Systeme (häufig handelt es sich um Rechencluster). Wenn AcceptEnv keinen Root-Zugriff erfordert hätte, würde ich zustimmen. Wie Sie unten sehen können, habe ich eine Lösung gefunden, die für alle außer \ n funktioniert. Ole Tange vor 11 Jahren 0
Ah, das macht Sinn. Danke für die Klarstellung. UtahJarhead vor 11 Jahren 0

2 Antworten auf die Frage

1
Ole Tange

Ich habe jetzt ein Arbeitsmodell für alle Zeichen außer \ 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/([\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\*\>\<\~\|\; \"\!\$\&\'\202-\377])/\\$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\"\$\`\*\174\!\?\~])/\\$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 . join(" && ", @qcsh) . q{ || } . join(" && ", @qbash) .q{;});  print shell_quote_scalar($Global::envvar); 
0
Darth Android

Können Sie einfach die Variable base64-encodieren? Der einfachste Weg, um damit umzugehen, besteht wahrscheinlich darin, die Daten einfach als binär zu behandeln.

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

Möglicherweise müssen Sie mit den Zitaten in der sshZeile herumtüfteln, aber das ist das Wesentliche. Dies sollte Shell-Besonderheiten in Bezug auf Zitate entfernen, könnte jedoch einige mit Unterbefehlen einführen (außerhalb von bash) bin ich nicht sehr vertraut.

Keine schlechte Idee. Wahrscheinlich kann ich nicht davon ausgehen, dass base64 installiert ist (base64 ist Teil von GNU coreutils und wurde erst 2006 eingeführt - daher können wir nicht davon ausgehen, dass es auf Nicht-GNU-Systemen und auf GNU-Systemen vor 2006 installiert ist). Ich kann jedoch davon ausgehen, dass eine alte Version von Perl installiert ist. Daher sollte das Packen mit dem "un * pack" mit der Vorlage "u *" machbar sein. Ole Tange vor 11 Jahren 0
uuencodierte Zeichenfolgen enthalten *. ARGH! Aber Hex-Code sollte funktionieren. Ole Tange vor 11 Jahren 0
Ich kann keinen Weg finden, um dies zu erreichen: Da der Befehl sowohl unter csh als auch unter bash arbeiten muss, muss ich ihn auswerten. Und sobald ich es evaliere, dann das * und? wird Probleme in csh verursachen. `echo setenv U`` perl -e '($ a = "212223c2a425262f28293d410a417b5b5d5d7e5e7e2a41") = ~ s / (..)/ chr hex $ 1 / eg; print $ a'` Ole Tange vor 11 Jahren 0
@OleTange Ist `openssl` verfügbar? http://hints.macworld.com/article.php?story=20030721010526390 Darth Android vor 11 Jahren 0
Nee. Aber selbst wenn base64 verfügbar war, konnte das Problem nicht behoben werden: Ich muss immer noch das eval durchführen und dieser Schritt bricht in (t) csh ein, wenn die Variable * oder? (Bash funktioniert gut und csh / tcsh auch, solange die Variable kein * oder? Enthält.) Ole Tange vor 11 Jahren 0