Команда b2 находит ICU при прямом вызове, но не из косвенной переменной сценария bash - PullRequest
0 голосов
/ 08 ноября 2018

У меня странная проблема с моим bash-скриптом. Я компилирую повышение как часть этого. Вызов из скрипта выглядит так:

./b2 --reconfigure ${PARALLEL} link=static cxxflags=-fPIC install boost.locale.iconv=off boost.locale.posix=off -sICU_PATH="${ICU_PREFIX}" -sICU_LINK="${BOOST_ICU_LIBS}" >> "${BOOST_LOG}" 2>&1

Эта команда работает отлично. Файл журнала показывает, что он находит ICU без проблем. Однако, если я изменю его для запуска из переменной, он больше не найдет ICU (но все равно скомпилирует все остальное):

bcmd="./b2 --reconfigure ${PARALLEL} link=static cxxflags=-fPIC install boost.locale.iconv=off boost.locale.posix=off -sICU_PATH=\"${ICU_PREFIX}\" -sICU_LINK=\"${BOOST_ICU_LIBS}\""
$bcmd >> "${BOOST_LOG}" 2>&1

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

Ответы [ 3 ]

0 голосов
/ 21 ноября 2018

Не используйте переменную для хранения сложных команд, включающих вложенные кавычки. Проблема в том, что когда вы вызываете переменную только с $cmd, кавычки удаляются неправильно. Поместить команды (или части команд) в переменные, а затем вернуть их нетронутыми, сложно.

Удаление кавычек является частью одного из расширений слов, выполняемых оболочкой. Из выдержки видно из POSIX спецификации оболочки

2.6.7 Удаление цитаты

Символы кавычек (обратная косая черта, одинарные кавычки и двойные кавычки), которые присутствовали в исходном слове, удаляются, если они сами не были заключены в кавычки.

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

cmdFlags='--archive --exclude="foo bar.txt"'

Если вы внимательно посмотрите выше, он содержит 2 аргумента, один --archive и другой для --exclude="foo bar.txt", обратите внимание на двойные кавычки, которые необходимо сохранить при прохождении.

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

printf "'%s' " $cmdFlags; printf '\n'
'--archive' '--exclude="foo' 'bar.txt"'

и сравните результат с результатами, приведенными ниже.

printf "'%s' " "$cmdFlags"; printf '\n'
'--archive --exclude="foo bar.txt"'

Таким образом, наряду с предложением правильно заключить в кавычки переменную, общим предложением было бы использовать массив для хранения флагов и передать расширение массива в кавычках

cmdArray=()
cmdArray=(./b2 --reconfigure ${PARALLEL} link=static cxxflags=-fPIC install boost.locale.iconv=off boost.locale.posix=off -sICU_PATH="${ICU_PREFIX}" -sICU_LINK="${BOOST_ICU_LIBS}")

и передать массив как

"${cmdArrray[@]}" >> "${BOOST_LOG}" 2>&1
0 голосов
/ 25 ноября 2018

Используйте одну квоту вместо двух.

bcmd='./b2 --reconfigure ${PARALLEL} link=static cxxflags=-fPIC install boost.locale.iconv=off boost.locale.posix=off -sICU_PATH=\"${ICU_PREFIX}\" -sICU_LINK=\"${BOOST_ICU_LIBS}\"'

В документации Bash говорится, что единичная квота не интерполируется:

3.1.2.2 Одинарные кавычки

Заключение символов в одинарные кавычки (') сохраняет буквальное значение каждого символа в кавычках. Одиночная кавычка может отсутствовать между одинарными кавычками, даже если ей предшествует обратная косая черта.

Таким образом, вы пропускаете двойную квоту для удаления и устранения проблемы, и ваша строка будет передана правильно. Если вы хотите использовать двойные кавычки, вы должны изменить, чтобы они НЕ сохраняли буквальное значение определенных символов: $, ' и \, если перед ними не стоит \, так как в ручном режиме указано:

3.1.2.3 Двойные кавычки

Заключение символов в двойные кавычки (") сохраняет буквальное значение всех символов в кавычках, за исключением $, `, \ и, когда включено расширение истории, !. Символы $ и ` сохраняют свое особое значение в двойных кавычках (см. Расширения оболочки ). Обратная косая черта сохраняет свое специальное значение только тогда, когда за ней следует один из следующих символов: $, `, ", \ или перевод строки. В двойных кавычках удаляются обратные слэши, за которыми следует один из этих символов. Обратная косая черта предшествующих символов без специального значения остается неизменной. Двойная кавычка может быть заключена в двойные кавычки, если им предшествует обратный слеш.

В вашем примере вы также забыли пометить $ обратной косой чертой. Разница между этими двумя понятиями прекрасно объясняется здесь Адамом: Разница между одинарной и двойной квотой

0 голосов
/ 19 ноября 2018

Попробуйте использовать eval, если хотите выполнить строку в качестве команды. Таким образом, у вас не будет проблем со строками, которые имеют пробелы и т. Д. Расширенная строка cmd не переоценивается bash, следовательно, такие вещи, как "hi there", раскрываются как два отдельных токена.

eval "$bcmd" >> "${BOOST_LOG}" 2>&1

Чтобы продемонстрировать это поведение, рассмотрите следующий код:

cmd='echo "hi there"'
$cmd
eval "$cmd"

Который выводит на:

"hi there"
hi there

Маркер "hi there" не переоценивается как строка в кавычках.

...