NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: bin/60499: printf(1) doesn't support positional arguments (%n$...)
The following reply was made to PR bin/60499; it has been noted by GNATS.
From: Robert Elz <kre%munnari.OZ.AU@localhost>
To: gnats-bugs%netbsd.org@localhost
Cc:
Subject: Re: bin/60499: printf(1) doesn't support positional arguments (%n$...)
Date: Sat, 25 Jul 2026 09:23:12 +0700
Date: Fri, 24 Jul 2026 21:30:01 +0000 (UTC)
From: "uwe%stderr.spb.ru@localhost via gnats" <gnats-admin%NetBSD.org@localhost>
Message-ID: <20260724213001.C55141A923D%mollari.NetBSD.org@localhost>
| printf(1) doesn't seem to support positional parameters "%n$..."
| Issue 8 seems to prescribe it:
It does. If it didn't, we would most likely have support!
The problem is that I simply find the spec in POSIX absurd, so rather
that implement that, I implemented (committed really) nothing.
Note that the issue doesn't affect any normal use of the things,
but would have affected your test case (potentially):
| printf '\tR%1$d, G%1$d = R%1$d,\n' $(seq 0 7)
That is, when there are more args (8 in that case) than are used
by the format string (just 1 here).
printf(3) is not affected at all by these issues, it never attempts
to repeat the format string, to use up all the args (it has no way to
determine how many of them there were) - one potential solution for
printf(1) would be to make it the same, so if there are any positional
args, the format string would only be used once.
The would easily deal with all the issues when the positional args are
being used for their original purpose - supporting output of i18n strings,
where different cultures output messages with the parameters in different
orders, and not necessarily using all of the args (any of them might be
omitted).
It wouldn't however handle people who have decided that printf(1)'s
positional params can be (ab)used to do all kinds of other tricks, like
the one you are attempting above, which could just as easily be
written
for A in $(seq 0 7)
do
printf '\tR%d, G%d = R%d,\n' "$A" "$A" "$A"
done
If you do it that way (and something like this is *always* possible
in these kinds of cases) there is never any ambiguity about what is
intended - there's just a little less opportunity to show off just
how clever you are.
There are other (not as simple as that one, but still relatively sane)
potential solutions, which are not as broken as what POSIX prescribes
however -- personally though I kind of like the simple elegance of
simply ignoring stray extra args when there are positional params, but
none happens to select the final args -- which can easily happen when
an internationised printf usage (where the format string comes from a
message catalog) and the language in question happens not to need the
final arg. printf(3) wouldn't care, printf(1) probably shouldn't either.
| $ printf: %1$: invalid directive
| R$
| PS: note also, how the format is not checked in advance and the initial
| prefix is printed.
That is actually a requirement. I agree in most cases a fairly silly one,
but in general printf(1) is always required to print everything it has
accumulated up to the time an error is detected (including bogus results
of conversions in many cases).
kre
Home |
Main Index |
Thread Index |
Old Index