[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: (cross post from bug-make) A complete example of quoting an arbitrar
From: |
Poor Yorick |
Subject: |
Re: (cross post from bug-make) A complete example of quoting an arbitrary value as a word in a shell script |
Date: |
Sun, 06 Nov 2022 00:34:58 +0200 |
The code in the original message on this topic didn't quite work: Its
uses of
double quotes meant that some characters were interpreted by the shell
as
special when they shouldn't have been. Below are three hopefully
correct
approaches, each one more simple than the preceding one.
This code is demonstrates a user-defined function, "shquote", that
quotes a value
for substitution into a shell script. It provides functionality similar
to
.ONESHELL, but without the disadvantage of changing the behaviour of all
recipes in all rules. Notably, heredocs can be used, which makes it
possible
to pass virtually any value from Make into a shell script.
One difference between the direct shell quoting and posix shell quoting
below
is that the direct shell quoting preserves trailing newlines while the
posix
shell quoting does not. There seems to be no way around that
difference.
Heredocs can be used to work around issues that might arise from the
loss of
trailing newlines.
<code>
SHELL = bash
#SHELL = dash
define newline
endef
define script0
echo 'line one \\
line two '
cat <<-'eof'
line three
line four
eof
$$var1
var2="line five"
printf '%s\n' "$$var2"
echo 'last
line'
endef
ifeq ($(shell printf '%s' $$'\n'),$$\n)
$(warning posix shell quoting, trailing newlines not preserved)
# this is more difficult
# one way to do it is to quote things enough the final printf
doesn't need to add newlines back
## replace each single quote with escaped single quote, and add an
extra layer of quoting for eval to strip off
#shquotequote = $(subst ','\\'\\\\\'\\'',$(1))
## replace each newline with command-substitution to produce a
newline enclosed in ingle quotes for eval to strip off
#shnlquote = \''$(subst $(newline),'$$(printf "'\n'")',$(call
shquotequote,$(1)))'\'
## during evaluation command substitution produces newlines, and a
layer of quoting is consumed
#shquote = "$$(eval eval printf "'%s'" "$(call shnlquote,$(1))")"
## another slightly more simple way is to let the final printf add
newlines back
## replace each single quote with escaped single quote, and add an
extra layer
## of quoting for eval to strip off
#shquotequote = $(subst ','\'\\\'\'',$(1))
## replace each newline with command-substitution to produce a
newline
## enclosed in ingle quotes for eval to strip off
#shnlquote = \''$(subst $(newline),'$$(printf "'\n'")',$(call
shquotequote,$(1)))'\'
## during evaluation command substitution produces newlines, and a
layer of
## quoting is consumed
#shquote = "$$(eval printf "'%sxxx\n'" $(call shnlquote,$(1)))"
# but even more simple is to forget about trying to encode each
newline with
# a $(printf), and just provide a space-separated sequence of quoted
values,
# each of which is a single line, and let a single printf add all
the
# newlines
shquotequote = $(subst ','\'',$(1))
shnlquote = '$(subst $(newline),' ',$(call shquotequote,$(1)))'
shquote = "$$(printf '%s\n' $(call shnlquote,$(1)))"
else
$(warning direct shell quoting, trailing newlines preserved)
# 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))
endif
script0:
eval $(call shquote,$(script0))
.PHONY: script0
printscript0:
printf '%s\n' $(call shquote,$(script0))
.PHONY: printscript0
</code>
--
Yorick
To support this and further work, make a payment to the following
Ethereum
address (Mainnet, ImmutableX Layer 2, or Loopring Layer 2 only):
0x0b5049C148b00a216B29641ab16953b6060Ef8A6
- Re: (cross post from bug-make) A complete example of quoting an arbitrary value as a word in a shell script,
Poor Yorick <=