Оценка ключ=значение с пробелами в $value в bash не удалась

В скрипте у меня есть функция, которая оценивает переданные параметры «ключ = значение», то есть:

function evaluateKeyValuePair() {
    eval "$1"
}

evaluateKeyValuePair "key=value with whitespaces"
evaluateKeyValuePair "key=value"

Последний вызов работает нормально, «echo $key» печатает «значение». Однако вызов функции с пробелами в «значении» не работает: для «с» и «пробелов» выдается ошибка «команда не найдена».

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

Я попытался изменить его на:

function evaluateKeyValuePair() {

    key="${1%%=*}"
    val2="${1#*"="}"

    eval $key="$val2"
}

но это тоже не работает.

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

СПАСИБО заранее!


person PuppetMaster    schedule 22.11.2015    source источник
comment
Это плохая идея; bash уже имеет способ передачи значений таким образом: key="value with whitespace" ./script сделает key доступным внутри script. Неясно, каков ваш фактический вариант использования, но это почти наверняка неправильное решение.   -  person chepner    schedule 22.11.2015
comment
Если вы читаете все эти строки из файла, есть ли в этом файле что-то еще? Не могли бы вы просто source файл вместо того, чтобы пытаться обработать его самостоятельно?   -  person Eric Renouf    schedule 22.11.2015
comment
@chepner: Ваше предложение не сработает, поскольку некоторые пары ключ-значение могут быть доступны только после запуска сценария или изменения во время выполнения.   -  person PuppetMaster    schedule 22.11.2015
comment
@Eric Renouf: К сожалению, есть строки с другими парами ключ-значение, и некоторые переменные не должны быть перезаписаны. Действительно, в функции есть тест, который проверяет, разрешена ли перезапись считываемой переменной или нет. Я просто бросил эту часть здесь.   -  person PuppetMaster    schedule 22.11.2015


Ответы (3)


В bash вы можете выполнить назначение, используя встроенный declare вместо eval. Это позволяет избежать необходимости вставлять экранированные кавычки в аргумент.

Обратите внимание, что в функции declare эквивалентно local, поэтому необходимо добавить флаг -g (глобальный) (реализован в версии 4.2; до этого вам приходилось использовать export, чтобы не делать переменную локальной):

evaluateKeyValuePair() {
  declare -g "$1"
}

Пример:

$ evaluateKeyValuePair "key=value with whitespaces"
$ echo "$key"
value with whitespaces
person rici    schedule 22.11.2015
comment
объявить -g просто идеально. Большое спасибо! - person PuppetMaster; 22.11.2015
comment
Обратите внимание, что declare -g доступен только в bash 4.2 или более поздних версиях. Кроме того, declare безопаснее, чем eval, но не совсем безопасно. - person chepner; 22.11.2015
comment
@chepner: я не утверждал, что это безопаснее; только это требует меньше внимания к цитированию. Добавлено требование версии; Благодарю. - person rici; 22.11.2015

Попробуйте использовать одинарную кавычку

function evaluateKeyValuePair() {
    eval "$1"
}

evaluateKeyValuePair 'key="value with whitespaces"'
evaluateKeyValuePair "key=value"

Вы также можете избежать двойных кавычек следующим образом:

evaluateKeyValuePair "key=\"value with whitespaces\""
person Luc M    schedule 22.11.2015
comment
Привет Люк! Спасибо за Ваш ответ. Это не сработает, так как обычно пары ключ-значение считываются из файлов. Так что мне пришлось бы преобразовывать строки в подходящие форматы, и я надеялся, что в этом нет необходимости. Иногда оценка необходима для проверки пользовательского ввода. Но вы ведете меня в правильном направлении: eval $key='$val2' работает как для key=value с пробелами, так и для key=value с пробелами. Большое спасибо за вашу поддержку! - person PuppetMaster; 22.11.2015

Со второй попыткой и ответом здесь вы можете делать то, что хотите, без eval:

function evaluateKeyValuePair() {
    key="${1%%=*}"
    val2="${1#*"="}"

    printf -v $key "$val2"
}

evaluateKeyValuePair "key=value with whitespaces"
printf "%s\n" "$key"

который напечатает value with whitespaces

person Eric Renouf    schedule 22.11.2015