help-make
[Top][All Lists]
Advanced

[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





reply via email to

[Prev in Thread] Current Thread [Next in Thread]