Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to embed a single quote in a makefile recipe?

20 views
Skip to first unread message

Kenny McCormack

unread,
Feb 2, 2018, 3:09:35 PM2/2/18
to
In make, I'm trying to do something like:

something:
gawk 'BEGIN { print "hello, world" }' > something

But it errs with a shell error message, because the above gets fed into a
shell via the usual: sh -c '...'
mechanism, so you end up with:

sh -c 'gawk 'BEGIN { print "hello, world" }' > something'

which obviously isn't right. I've tried every manner of quoting and
backslashing I can think of but nothing works.

How to do this?

--
Marshall: 10/22/51
Jessica: 4/4/79

Kaz Kylheku

unread,
Feb 2, 2018, 4:05:32 PM2/2/18
to
On 2018-02-02, Kenny McCormack <gaz...@shell.xmission.com> wrote:
> In make, I'm trying to do something like:
>
> something:
> gawk 'BEGIN { print "hello, world" }' > something
>
> But it errs with a shell error message, because the above gets fed into a
> shell via the usual: sh -c '...'

But -c is a "clean" mechanism for passing through a piece of script!

It works for me verbatim. I copy and pasted that command into a Makefile
recipe, ran it, and the "something" file got created with "hello, world"
in it.

Are you using GNU Make?

Here is what a GNU make job looks like under strace:

4528 vfork() = 4530
4530 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
4528 rt_sigprocmask(SIG_SETMASK, [], <unfinished ...>
4530 execve("/bin/sh", ["/bin/sh", "-c", "if true; then echo common
recipe"...]

The rule I have is something like:

target:
... commands ..
if true; then echo common recipe; fi

You can see that the whole command turns into a single argv[] element.

No single quotes are inserted into it; it is null-terminated C string
object in which the only character we cannot have is NUL, and nothing
requires escaping.

> mechanism, so you end up with:
>
> sh -c 'gawk 'BEGIN { print "hello, world" }' > something'

Not with GNU Make; maybe you have some make which does this?

If I add some single quotes to the command, I get this:

4570 vfork() = 4572
4572 execve("/bin/sh", ["/bin/sh", "-c", "if true; then echo 'common
recip"...]

It works perfectly.

Kenny McCormack

unread,
Feb 2, 2018, 7:43:21 PM2/2/18
to
In article <201802021...@kylheku.com>,
Kaz Kylheku <217-67...@kylheku.com> wrote:
>On 2018-02-02, Kenny McCormack <gaz...@shell.xmission.com> wrote:
>> In make, I'm trying to do something like:
>>
>> something:
>> gawk 'BEGIN { print "hello, world" }' > something
>>
>> But it errs with a shell error message, because the above gets fed into a
>> shell via the usual: sh -c '...'
>
>But -c is a "clean" mechanism for passing through a piece of script!

Why say this?
Did anything I wrote imply that I thought otherwise?

>It works for me verbatim. I copy and pasted that command into a Makefile
>recipe, ran it, and the "something" file got created with "hello, world"
>in it.

Yes, I think you are right. I know this was happening earlier today (using
a different, more complex script - the details of which are no longer
recoverable), but I can't replicate it now (using the simple "hello, world"
example).

So, we may have to chalk this one up to the Journal of Irreproducible Results.

--
Genesis 2:7 And the LORD God formed man of the dust of the ground, and
breathed into his nostrils the breath of life; and man became a living soul.

Kaz Kylheku

unread,
Feb 2, 2018, 9:03:51 PM2/2/18
to
On 2018-02-03, Kenny McCormack <gaz...@shell.xmission.com> wrote:
> In article <201802021...@kylheku.com>,
> Kaz Kylheku <217-67...@kylheku.com> wrote:
>>On 2018-02-02, Kenny McCormack <gaz...@shell.xmission.com> wrote:
>>> In make, I'm trying to do something like:
>>>
>>> something:
>>> gawk 'BEGIN { print "hello, world" }' > something
>>>
>>> But it errs with a shell error message, because the above gets fed into a
>>> shell via the usual: sh -c '...'
>>
>>But -c is a "clean" mechanism for passing through a piece of script!
>
> Why say this?
> Did anything I wrote imply that I thought otherwise?

Yes.

I was under the impression that you believe (possibly rightly so) that
your make is wrapping the -c argument in single quotes.

The above remark is related to that, though not in a clear way.

William Ahern

unread,
Feb 5, 2018, 4:15:10 AM2/5/18
to
> ^B4570 vfork() = 4572
> 4572 execve("/bin/sh", ["/bin/sh", "-c", "if true; then echo 'common
> recip"...]
>
> It works perfectly.

This behavior is required by POSIX, which says

The execution line shall then be executed by a shell as if it were
passed as the argument to the system() interface....

and

The system() function shall behave as if a child process were created
using fork(), and the child process invoked the sh utility using
execl() as follows:

execl(<shell path>, "sh", "-c", command, (char *)0);

I've never encountered an implementation that didn't behave this way,
including AIX make, OpenBSD make, NetBSD make (also used in FreeBSD), and
Solaris make.

Likely the original problem was a make macro containing quotes expanding
within the quoted segment.
0 new messages