9

У меня есть команда, хранящаяся в переменной. Давайте представим, что переменная $i имеет значение:

cat -nT index.php |grep 'someregex'

Когда я пытаюсь выполнить указанную выше переменную, набирая $i это терпит неудачу, потому что оболочка пытается выполнить всю переменную как одну команду. Я также попытался использовать eval($i) и положить $i в кавычки.

Как заставить оболочку выполнить $i как если бы это была команда? И почему это не работает так же, как.

$i='echo hi'; $i

Это потому, что мне пришлось взламывать одинарные кавычки? (Потому что вы не можете их вложить.) В настоящее время мое решение

echo $i > /foo;  . /foo

Но я не хочу создавать файл только для этого, чтобы потом удалить его.

Что я имею в виду под "я взломал в одиночных кавычках, я сделал:

$i='cat index.php | grep -P '"'"'MYREGEXHERE'"'"

3 ответа3

15

Краткий ответ: см. BashAQ # 50: я пытаюсь поместить команду в переменную, но сложные случаи всегда терпят неудачу! ,

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

Чтобы решить эту проблему, вам нужно ответить на вопрос @ slhck: почему команда хранится в переменной в первую очередь? Какую реальную проблему вы пытаетесь решить? В зависимости от конкретной цели, существует ряд возможных решений:

  • Не храните его в переменной, просто выполняйте его напрямую. Хранить команды для последующего использования сложно, и если вам это не нужно, просто не делайте этого.

  • Используйте функцию вместо переменной. Вот для чего они, в конце концов:

    i() { cat -nT index.php |grep 'someregex'; }
    i
    

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

  • Используйте eval . Это следует считать последним средством, поскольку легко получить неожиданное поведение. По сути, он запускает команду через еще один полный этап синтаксического анализа, поэтому все каналы и т.д. Получают свое полное значение - но это также означает, что части команды, которые вы считали просто данными, также будут проанализированы и, возможно, выполнены. Имена файлов, содержащие метасимволы оболочки (труба, точка с запятой, цитата / апостроф и т.д.), Могут иметь странные и иногда опасные последствия. Если вы используете eval , по крайней мере сделайте двойную кавычку в строке, в противном случае ее содержимое будет проанализировано полтора раза, что приведет к еще более странным результатам.

    i="cat -nT index.php |grep 'someregex'"
    eval "$i"
    

РЕДАКТИРОВАТЬ: Другой стандартный подход хранилища-команда-в-переменной заключается в использовании массива вместо простой переменной. Это позволяет без проблем хранить команды со сложными аргументами (например, содержащими пробелы), но не будет хранить такие вещи, как каналы и перенаправления. Таким образом, подход массива не будет полезен в этом конкретном случае.

4

Это должно просто работать:

a="cat -nT index.php |grep 'someregex'"
eval "$a"

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

3

При объявлении переменной не следует использовать знак доллара в качестве префикса.

Попробуй это:

i='echo hi'; $i

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .