Хотя export
не очень хорошо играет с $(shell ...)
, существует простой обходной путь. Мы можем передать данные в сценарий оболочки через командную строку.
Теперь, конечно, прохождение среды устойчиво к проблемам экранирования и цитирования. Однако в языке оболочки есть метод кавычек с одинарными кавычками '...'
, который обрабатывает все. Единственная проблема в том, что там нет способа получить одинарную кавычку; но, конечно, это решается завершением кавычки, экранированием обратной косой черты необходимой одинарной кавычкой и началом новой кавычки: Другими словами:
ab'cd -> 'ab'\''cd'
В сценарии оболочки, выполняемом $(shell ...)
, мы просто генерируем присвоение переменной в форме var='$(...)'
, где $(...)
- это некоторое выражение make, которое интерполирует подходящим образом экранированный материал. Таким образом, Makefile
:
somevar := apple with 'quoted' "stuff" and dollar $$signs
shell_escape = $(subst ','\'',$(1))
update := $(shell v='$(call shell_escape,$(somevar))'; echo $$v > file.txt)
.phony: all
all:
cat file.txt
Пример прогона:
$ make
cat file.txt
apple with 'quoted' "stuff" and dollar $signs
Если мы хотим передать переменную окружения команде, мы можем сделать это, используя синтаксис оболочки VAR0=val0 VAR1=val1 ... VARn=valn command arg ...
. Это может быть проиллюстрировано некоторыми незначительными изменениями в Makefile
:
somevar := apple with 'quoted' "stuff" and dollar $$signs
shell_escape = $(subst ','\'',$(1))
update := $(shell somevar='$(call shell_escape,$(somevar))' env > file.txt)
.phony: all
all:
grep somevar file.txt
Пробег:
$ make
grep somevar file.txt
somevar=apple with 'quoted' "stuff" and dollar $signs
file.txt
содержит дамп переменных среды, где мы можем увидеть somevar
. Если бы export
в GNU Make поступил правильно, мы могли бы просто сделать:
export somevar
update := $(shell env > file.txt)
но конечный результат тот же.
Поскольку конечный результат, который вам нужен, равен echo $(update)
, вы все равно бы shell_escape
, даже если GNU Make передал экспортированные переменные в $(shell ...)
. То есть посмотрите на еще один Makefile
:
somevar := apple with 'quoted' "stuff" and dollar $$signs
shell_escape = $(subst ','\'',$(1))
update := $(shell v='$(call shell_escape,$(somevar))'; echo $$v)
.phony: all
all:
@echo '$(call shell_escape,$(update))'
@echo $(update)
Выход:
apple with 'quoted' "stuff" and dollar $signs
apple with quoted stuff and dollar