Передача переменной среды через SSH / цитирование в bash / sh / csh / tcsh

Я хочу передать переменную среды через SSH.

«Правильным» способом является использование SendEnv / ~/.ssh/environment , но для этого требуется, чтобы сервер поддерживал AcceptEnv или PermitUserEnvironment, чего нет в моем случае.

Поэтому вместо этого я хочу установить переменную на удаленном сайте следующим образом:

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

Эта часть проста. Я хочу универсальное решение, поэтому независимо от содержания FOO он будет работать. Например

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

Это работает независимо от того, является ли отправляющая или принимающая оболочка sh или bash.

Тем не менее, мне также нужно, чтобы он работал для csh / tcsh. И я не буду заранее знать, какая оболочка получает приемный конец. Это означает, что я должен закодировать что-то, что будет работать как в / bin / sh, так и в / bin / csh.

До сих пор мне удалось заставить его работать для 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" 

Я также могу заставить его работать для csh / tcsh (пользователь csh имеет csh в качестве оболочки входа):

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

Если $ FOO * или? Он отлично работает с BASH:

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

Но это не с помощью csh:

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

Кажется * и? Отказаться от цитирования.

Чтобы ответить на этот вопрос, ваше решение должно:

  • Иметь возможность передавать переменную окружения на удаленный сервер
  • Не использовать SendEnv / AcceptEnv / PermitUserEnvironment
  • Работа независимо от того, является ли исходная оболочка sh / bash / csh / tcsh
  • Работа независимо от того, является ли целевая оболочка sh / bash / csh / tcsh
  • Работать независимо от содержимого переменной окружения. В частности, он должен, по крайней мере, работать для: \ n * space '"? <>! $ \ И любой их комбинации.

Если вы можете найти лучший способ передачи переменной, чем цитирование ее, то это тоже хорошо.

    Теперь у меня есть рабочая модель для всех символов, кроме \ 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{echo $SHELL | grep -E "/t?csh" > /dev/null && } . join(" && ", @qcsh) . q{ || } . join(" && ", @qbash) .q{;}); print shell_quote_scalar($Global::envvar); - 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{echo $SHELL | grep -E "/t?csh" > /dev/null && } . join(" && ", @qcsh) . q{ || } . join(" && ", @qbash) .q{;}); print shell_quote_scalar($Global::envvar); 

    Можете ли вы просто base64-кодировать переменную? Самый простой способ справиться с этим – это, вероятно, просто обрабатывать данные как двоичные.

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

    Возможно, вам придется возиться с цитированием на линии ssh , но это и есть суть этого. Это должно удалить спецификацию оболочки в отношении цитирования, но может ввести некоторые из подкоманд (я не очень хорошо знаком с чем-либо вне bash )

    Давайте будем гением компьютера.