Предотвращение преждевременного расширения параметров оболочки в цепочках команд

У меня есть система, которая позволяет выполнять команды с хоста на различные внешние машины из сценария оболочки bash с использованием ssh или 'sersh', который похож на ssh, но отправляет команды через последовательный порт. (Детали этих команд не имеют значения.)

Я пытаюсь связать команды вместе, с одной внешней машины на третью машину. Мне трудно понять, как заставить оболочку расширять параметры только на конечной машине.

function do_cmd () {
    case $TRANSPORT in
        ssh)
            ssh -i ${SSH_KEY} ${LOGIN}@${IPADDR} "$@"
            ;;
        serial)
            sersh ${SER_LOGIN}@{SERIAL_DEV} "$@"
            ;;
        ssh2serial)
            ssh -i ${SSH_KEY} ${LOGIN}@{IPADDR} \
               "sersh ${SER_LOGIN}@${SERIAL_DEV} $@"
            ;;
        *)
            echo "Unknown transport $TRANSPORT"
            ;;
    esac
}

do_cmd "echo hello"
do_cmd "echo \"my pid is \$\$\""
do_cmd "cd /proc ; for pid in 1* ; do echo \$pid, ; done"

Все три из этих вызовов работают правильно, когда TRANSPORT имеет значение «ssh» или «serial». Для TRANSPORT 'ssh2serial' во втором вызове do_cmd значение $$ расширяется преждевременно (на промежуточной, а не на конечной машине). И для третьего вызова do_cmd $pid заканчивается пустой строкой до того, как цикл будет выполнен на последней машине.

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


person Tim Bird    schedule 12.02.2019    source источник
comment
Что такое sersh? Если бы это были две команды ssh, я бы рекомендовал ssh -o ProxyCommand="ssh login1@host1" login2@host2 ... вместо ssh login1@host1 "ssh login@host2 ...", но я не знаю, есть ли что-то подобное для sersh.   -  person chepner    schedule 12.02.2019
comment
sersh взят из инструмента serio (github.com/frowand/serio). Он не поддерживает ProxyCommand. Однако то, что вы предлагаете, может сработать, потому что мой вариант использования всегда использует ssh для первой машины и sersh для второй машины оттуда. Я попробую. Спасибо за совет!   -  person Tim Bird    schedule 13.02.2019
comment
Документация для ProxyCommand (см. man ssh_config) дает пример nc в качестве команды, так что это может работать; У меня просто нет возможности проверить или подтвердить это. (Я думаю, что он ожидает, что конечный хост все еще будет работать под управлением sshd, что, однако, не будет иметь место для вашего последовательного устройства.)   -  person chepner    schedule 13.02.2019


Ответы (1)


[@MadPhysicist напоминает мне, что мне все равно придется избегать расширений переменных. Мой ответ оставлен здесь ниже для справки, но @MadPhysicist прав: мой ответ, вероятно, не отвечает на заданный вопрос.]

Используйте 1_.

Попробуйте это упражнение, введя следующие четыре команды в командной строке вашей оболочки. Я полагаю, что упражнение, вероятно, ответит на ваш вопрос.

$ X=55
$ A='echo $(( $X + $X ))'
$ echo "$A"
$ eval "$A"

Как только упражнение покажет вам, что делает встроенная команда оболочки eval, вы можете получить желаемый эффект, используя eval на последнем компьютере в вашей цепочке.

[Обратите внимание, что в упражнении написано A='echo $(( $X + $X ))'. Это не говорит, A=`echo $(( $X + $X ))`. Обратите внимание на наклон кавычек. Здесь вам нужны обычные одинарные кавычки, а не обратные кавычки.]

person thb    schedule 12.02.2019
comment
Вам все равно придется избегать расширений переменных - person Mad Physicist; 13.02.2019
comment
Спасибо. Это привело меня к решению, я считаю. Я заключил в одинарные кавычки последний «$@» в случае ssh2serial, и это предотвратило его расширение на промежуточном хосте: ssh -i ${SSH_KEY} ${LOGIN}@{IPADDR} sersh ${SER_LOGIN}@$ {SERIAL_DEV} '$@'. Сейчас я тестирую его с множеством разных команд. - person Tim Bird; 13.02.2019
comment
Хорошо. Это eval иногда может быть полезно, не так ли? Когда у вас будет время, если вы либо отредактируете мой ответ с учетом того, что вы обнаружили, либо опубликуете свой собственный ответ, это поможет. - person thb; 13.02.2019
comment
ОК - ваш ответ дает 2 совета: один о «eval», который я не использовал, а другой об одинарных кавычках, которые я в итоге использовал, и которые хорошо решили проблему для меня. Каков наилучший путь вперед? Я хотел бы принять ответ, но обратите внимание на часть, которая сработала. То есть я хотел бы сказать, что одинарных кавычек было достаточно, а «eval» не было необходимости. Это делается более уместно как редактирование вашего ответа или новый ответ. (Я никогда раньше не редактировал чужой ответ, поэтому не знаю, насколько это уместно.) Спасибо. - person Tim Bird; 16.02.2019
comment
Достаточно нового ответа. Когда у вас будет время, просто напишите новый ответ и примите его. Это должно сработать. - person thb; 17.02.2019