2016-09-14 10 views
0

Команды:Скобки для субоболочки не работает при хранении в переменной

(echo 1) 

отлично работает, когда я его ввод в командной строке, но если хранить его в качестве переменного и назвать его, это дает ошибка:

(echo: command not found 

Код:

input="(echo 1)" 
$input 

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

+1

См [BashFAQ # 50] (Http: // mywiki.wooledge.org/BashFAQ/050). Некотированное расширение распространяется только на два этапа разбора (разложение поля и расширение glob); это верно по очень веским причинам (было бы гораздо сложнее написать защищенный код в bash в противном случае). Связанные FAQ подробно рассматриваются, в том числе обсуждение лучших практик для случаев, когда вы могли бы захотеть сохранить код в переменной. –

+4

Вы не можете поместить такие команды в переменную. Фактически, размещение команд в переменных подвержено ошибкам. Переменные сохраняют _data_, а не _commands! _, Если вы хотите хранить команды где-то для будущего использования, используйте _function._ –

+1

Кстати, ваш код и ваша ошибка не выстраиваются в линию. Вы будете получать '(: command not found', если вы использовали точный код, указанный здесь. Обязательно скопируйте/вставьте код в свой вопрос * точно так, как было задано *, чтобы избежать таких ситуаций в будущем, в случаях, когда эти различия могут иметь значение. –

ответ

0

Скобки представляют собой синтаксис оболочки.

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

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

Например, рассмотрим следующее:

arg="(parenthesized)" 
somecommand $arg 

Мы просто хотим somecommand быть вызван с символьной строки (parenthesized) в качестве аргумента; мы не хотим запускать подоболочку. Такой неявный eval превратит безвредные данные в живой код, создавая дыру в безопасности, не говоря уже о кошмарном кодировании, чтобы попытаться избежать этого.

Правила обработки $arg не зависят от положения; расширение происходит таким же образом, даже если $arg является первым элементом в командной строке:

$arg foo 

замена параметров превращает $arg в текст (parenthesized), а затем, что пробуется в качестве команды, а не как синтаксис оболочки.

Чтобы выполнить часть скрипта, хранящегося в input, используйте:

eval "$input" 

Вы также можете сделать это следующим образом:

input="echo 1"  # no parentheses 

/bin/sh -c "$input" # run in subshell explicitly 

Конечно, подоболочка подход подает фрагмент кода в ту же оболочку, которая выполняет окружающий скрипт, тогда как здесь мы выбрали /bin/sh, который может отличаться от вызывающей оболочки или иметь другое поведение, даже если это символическая ссылка на ту же оболочку.

+0

Поскольку 'command' является встроенным, использование его как standin для некоторой-random-other-command немного запутанно. –

+0

@CharlesDuffy Это отличная точка, сэр, она должна быть исправлена. – Kaz

1

Это подробно обсуждается в BashFAQ #50.

Несвоевременное расширение проходит только через два этапа разбора оболочки: Разделение поля и расширение glob.Таким образом, (echo 1) сначала разделяется на поля: (, echo, 1 и ); каждый расширяется как глобус (спорный, поскольку ни одно из них не является расширением глобуса); а затем они запускаются как команда: ( вызывается с первым аргументом echo, вторым аргументом 1 и третьим аргументом ).

Правильный способ для хранения кода в функции:

# best-practices approach 
input() (echo 1;) 
input 

... или, если вы хотите, чтобы сделать его более явным для человеческого читателя, что вы действительно хотите подоболочку и weren» т с помощью скобок, а не брекеты по ошибке или привычки:

# same, but more explicit about intent 
input() { (echo 1); } 
input 

... если это невозможно, можно использовать eval (но будьте осторожны с оговорками, приведенными в BashFAQ #48):

# avoid this approach if at all possible 
input="(echo 1)" 
eval "$input" 

Если реальная причина, вы создаете команду в строке является параметризация его содержимое, использовать массив вместо:

input_args=(1)     # define an array 
input() (echo "${input_args[@]}") # use that array in a function (if needed) 

# add things according to conditional logic as appropriate 
if ((2 > 1)); then 
    input_args+=("possible argument here") 
fi 

# call the function, or just use the array directly, such as: (echo "$(input_args[@]}") 
input