Вывод на переменную с помощью косвенной команды (eval)

Что не так с этой косвенной командой при запуске с eval?

#!/bin/bash OS=AIX host=myhost CMD_AIX="(o=\`host \"$host\" \`)" CMD=\$CMD_$OS echo $CMD eval echo $CMD eval "$CMD" 

Ouput:

 $ myscript.sh $CMD_AIX (o=`host "myhost" `) myscript.sh: line 12: (o=`host: command not found 

EDIT – ПРИМЕЧАНИЯ: он находится в очень гетерогенной структуре с примерно 40 серверами, смешивая SCO, AIX и Linux, несколько версий каждого, включая варианты 32 и 64 бит. SCO и AIX не могут быть обновлены. Оболочка Bash и Korn распространена на всех серверах, но я ограничена версией 3 bash (в SCO), Ksh имеет несколько различий между ними, поэтому мы предпочитаем bash, которые не поддерживают ассоциативные массивы в v3 (это не могут быть обновлены, и это вне моих решений, и эти серверы будут заменены на AIX 7 и Linux через несколько месяцев).

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

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

Пример кода выше – это всего лишь принятый фрагмент, это не настоящий код. Пожалуйста, не рассматривайте логику, просто проблему косвенности (eval).

РЕШЕНИЕ: У меня есть решение, которое отлично работает, просто цепляя eval , например:

 torun=`eval $CMD` output=`eval torun` 

Этот ответ и еще один , который работал очень хорошо и отвечал на вопрос, были странно проголосовали много.

  • Превращение стандартного вывода в одну команду
  • Unix: проблема с командой cmp
  • Есть ли способ заставить скрипт Bash ввести определенное нажатие клавиши?
  • Можно ли получить сертификаты letencrypt с помощью сценария оболочки?
  • Найти все репозитории git, которые не содержат ни одного из .gitignore и .gitattributes
  • поиск и замена текста
  • Как учесть env vars shell-session, контексты с chroot
  • bash one-liner: установить переменную на вывод команды или значение по умолчанию, если вывод пуст
  • 5 Solutions collect form web for “Вывод на переменную с помощью косвенной команды (eval)”

    Таким образом, у вас есть переменная CMD , значением которой является строка $CMD_AIX , а значение переменной CMD_AIX – это строка (o=`host "myhost" `) . Вы хотите интерпретировать значение CMD_AIX в качестве команды оболочки и выполнить ее.

    Чтобы выполнить значение CMD_AIX в качестве команды оболочки, вам нужно создать команду оболочки, которая делает это. Вот что такое eval для:

     eval "$CMD_AIX" 

    Эта команда, в свою очередь, построена динамически. Поэтому вам нужно запустить его с помощью eval :

     dispatcher=… eval "$dispatcher" 

    Учитывая способ построения внутренней команды, мы получаем

     dispatcher="eval \"\$CMD_$OS\"" eval "$dispatcher" 

    Или вырезать одну переменную:

     eval "eval \"\$CMD_$OS\"" 

    Обратите внимание, что команда (o=`host "myhost" `) бессмысленна: она назначает вывод host переменной o в подоболочке; значение не предоставляется вне подоболочки. Удалите круглые скобки. Кроме того, host \"$host\" является странным: вы помещаете значение переменной host между двойными кавычками; это не имеет значения, поскольку имена хостов не содержат специальных символов оболочки, но для использования значения переменной при оценке фрагмента оболочки вы должны оставить нерасширенный здесь узел.

     #!/bin/sh OS=AIX # should probably be OS=`uname -r` host=myhost CMD_AIX="o=\`host \"\$host\"\`" eval "eval \"\$CMD_$OS\"" 

    Если у вас есть ksh93 или bash ≥ 4.0, вы можете упростить этот скрипт, используя ассоциативные массивы. Вместо того, чтобы набивать код для каждой операционной системы в другую переменную, поместите их в ассоциативный массив .

     #!/usr/bin/env bash typeset -A commands commands[AIX]="o=\`host \"\$host\"\`" OS=AIX host=myhost if [ -n "${commands[$OS]}" ]; then eval "${commands[$OS]}" else echo >&2 "Operating system $OS not supported" exit 2 fi 

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

    В любом случае, как у вас есть все ваши цитаты, написанные вами, вы защищаете что-либо от второй оценки. Или, скорее, вы полностью защищаете первый проход – и поэтому ничего не происходит до второго прохода. Проблема заключается в том, что вы можете просто не выполнять вторую оценку (и второй уровень кавычек) вообще.

    Мне кажется, что вы пытаетесь запустить определенную команду на основе значения $OSможет быть …? Ну, это одна из самых доступных функций API в оболочке.

    Например:

     OS=AIX host=myhost _cmd_AIX() { host "$host"; } _cmd_WIN() { exit "$((LOSE=1))"; } 

    Вы видите – вы можете запускать указанные определенные функции. Их имя команды не нуждается в каком-либо специальном втором интерпретаторе, чтобы иметь значение – даже когда это происходит в результате расширения. Он просто должен находиться в командном положении. Они все равно даже будут принимать параметры таким образом – так что вы могли бы передать $host как $1 если хотите. Вы просто называете это следующим образом:

     "_cmd_$OS" 

    $OS var будет расширяться до AIX и полученное командное слово будет _cmd_AIX – это предопределенная функция оболочки, имя которой происходит в целом и правильно разграниченное слово оболочки в командном положении – и поэтому оно выполняется. Просто так. Никаких искажений не требуется – и он даже поставляется с собственным массивом.

    Переопределить $OS в любое время на имя какого-либо другого действительного суффикса для других видов поведения.

    С zsh :

     $ echo $CMD $CMD_AIX $ echo ${(e)CMD} (o=`host "myhost" `) $ echo ${(e)${(e)CMD}} (o=myhost has address 1.2.3.4) 

    Флаг расширения (e) – это вычисление разложений в значении расширяемой переменной.

    С ksh93:

     $ function CMD.get { eval ".sh.value=\"$_\""; } $ function CMD_AIX.get { eval ".sh.value=\"$_\""; } $ echo "$CMD_AIX" (o=myhost has address 1.2.3.4) $ echo "$CMD" (o=myhost has address 1.2.3.4) $ CMD=\$USER $ echo "$CMD" stephane 

    CMD.get – это функция дисциплины, которая вызывается в любое время, когда расширяется $CMD обычно используется для определения того, что должно быть для этого расширения, чтобы позволить переменным с динамическим контентом. Здесь мы определяем его как возвращающий оценку его содержимого в двойных кавычках (который предполагает, что значение не содержит двойных кавычек).

    Вы также можете использовать типы:

     typeset -T evaluating_variable=( function get { eval ".sh.value=\"$_\""; } ) OS=AIX host=myhost evaluating_variable CMD_AIX='(o=`host "'$host'"`)' evaluating_variable CMD=\$CMD_$OS 

    Теперь, почему вы хотите сделать это в сценарии оболочки, другое дело.

    eval eval $CMD вместо последней строки исправляет проблему

    Это фиксировало проблему:

     eval `eval echo $CMD` 

    вместо:

     eval "$CMD" 
    Linux и Unix - лучшая ОС в мире.