[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
(cross post from bug-make) A complete example of quoting an arbitrary va
(cross post from bug-make) A complete example of quoting an arbitrary value as a word in a shell script
Wed, 26 Oct 2022 21:57:55 +0300
Posted this already to bug-make, but should have posted here in the
Maybe this has been done before, but I couldn't find it on the nets.
example Makefile below illustrates how to quote an arbitrary value as a
a shell script. One use case for this is to evaluate a value as a
shell script, similar to .ONESHELL but allowing all shell features,
heredocs. Surely there are many use cases.
The process to quote a value is:
Escape single quotes.
If $'\n' notation is available in the shell, use that.
Otherwise, enclose newlines in single quotes.
Enclose everything else in Single quotes.
In a Posix shell, where $'...' is not available it's tricky because
are stripped from the result of a command subsitution, so $(printf '\n')
does not work directly. The workaround used below is to have printf
produce both the
a newline and the single quotes that enclose it. For example, the
is transformed into,
and can be evaluated>
eval 'echo '\''hello'\''
Here is an example Makefile>
#SHELL = bash
SHELL = dash
echo 'line one
ifeq ($(shell printf '%s' $$'\n'),$$\n)
$(warning posix shell quoting)
# this is more difficult
# Assume $(1) will be enclosed in single quotes, break each single
# out of the enclosing quotes, and replace it with an escaped single
shquotequote = $(subst ','\'',$(1))
# Assume $(1) will be enclosed in single quotes, break each newline out
# the enclosing quotes, and replace it with a command substitution that
# produces a newline enclosed in single quotes. This results in some
# syntactically unnecessary quoting, but avoids having newline
# stripped from the result of the command substitution.
shnlquote = $(subst $(newline),'$$(printf "'\n'")','$(call
# Just print the string using printf, using eval to perform the newline
# command subsitutions and strip away the extra layer of quoting added
# shnlquote and shquotequote.
shquote = "$$(eval printf '%s' "$(call shnlquote,$(1))")"
$(warning direct shell quoting)
# this is easy...
# Replace each single quote with a quoted single quote,
# call shnlquoe to deal with newlines
# Add the first and last single quotes
shquote = '$(call shnlquote,$(subst ','"'"',$(1)))'
# replace each newline character with a
shnlquote = $(subst $(newline),'$$'\n'',$(1))
eval $(call shquote,$(script0))
printf '%s\n' $(call shquote,$(script0))
The following quoting implementation also works, but was discarded in
the one above:
# In a posix shell $'\n' is not a valid representation of newline, and
# isn't possible to produce a newline using command substitution because
# newlines are stripped off the result. Instead, use printf to replace
# newline character surrounded by double quotes.
shnlquote = $(subst $(newline),'\'$$(printf '"\n"')\'',$(1))
# Because each newline character is enclosed in an additional layer of
# quotes, enclose everything else in an additional layer of quotes too.
shquotequote = \''$(call shnlquote,$(subst ','\'\"\'\"\'',$(1)))'\'
# Finally, Use printf again to remove the extra layer of quoting, with
# effect here not being printf, but the quote removal that the shell
# performs as it reads the script.
shquote = "$$(printf '%s\n' $(call shquotequote,$(1)))"
To support this and further work, make a payment to the following
address (Mainnet, ImmutableX Layer 2, or Loopring Layer 2 only):
|[Prev in Thread]
||[Next in Thread]|
- (cross post from bug-make) A complete example of quoting an arbitrary value as a word in a shell script,
Poor Yorick <=