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

2612
Ole Tange

Я хочу передать переменную среды через 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 csh@server // 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 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. 

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

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

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

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

3
Похоже, мы делаем твою домашнюю работу. Почему вы не можете использовать опции ssh SendEnv или AcceptEnv? Вот для чего они предназначены. UtahJarhead 11 лет назад 0
Он должен использоваться для --env в GNU Parallel. GNU Parallel используется примерно 25000 пользователей. Многие из этих пользователей не имеют корневого доступа в системах, которые они используют (часто это вычислительные кластеры). Если бы AcceptEnv не требовал root-доступа, я бы согласился. Как вы можете видеть ниже, я нашел решение, которое работает для всех, кроме \ n. Ole Tange 11 лет назад 0
Ах, это имеет смысл. Спасибо за разъяснения. UtahJarhead 11 лет назад 0

2 ответа на вопрос

1
Ole Tange

I now have a working model for all characters except \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

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

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

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

Неплохая идея. Хотя я, вероятно, не могу предположить, что base64 установлен (base64 является частью ядра GNU Coreutils и появился только в 2006 году - поэтому мы не можем предполагать, что он установлен в системах без GNU и в системах GNU до 2006 года). Однако я могу предположить, что установлена ​​старая версия Perl, поэтому используйте (не) пакет с шаблоном "u *", что должно быть выполнимо. Ole Tange 11 лет назад 0
UUEN кодированные строки включают *. ARGH! Но закодированный hex должен работать. Ole Tange 11 лет назад 0
Я не могу найти способ заставить это работать: поскольку команда должна работать как с csh, так и с bash, мне нужно проверить ее. И как только я это сделаю, тогда * и? вызовет проблемы в csh. `echo setenv U`` perl -e '($ a = "212223c2a425262f28293d410a417b5b5d7d5e7e2a41") = ~ s /(..)/ chr hex $ 1 / например; напечатать $ a'` Ole Tange 11 лет назад 0
@OleTange Доступен ли `openssl`? http://hints.macworld.com/article.php?story=20030721010526390 Darth Android 11 лет назад 0
Нету. Но даже если бы base64 был доступен, это не решило бы проблему: мне все еще нужно сделать eval, и именно этот шаг нарушает (t) csh, если переменная содержит * или? (Bash работает нормально, как и csh / tcsh, если переменная не содержит * или?). Ole Tange 11 лет назад 0

Похожие вопросы