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

funnies.sh

216 views
Skip to first unread message

Mike Sanders

unread,
Jan 14, 2018, 10:52:05 AM1/14/18
to
#!/bin/sh

<<about
funnies.sh - 2018 Michael Sanders
creates a webpage of 'funnies'
beware wordwrap & enjoy =)
about

f=funnies.html
d=$(date +%d)
m=$(date +%m)
y=$(date +%Y)

cat <<top >$f
<html>
<head>
<title>funnies: $y/$m/$d</title>
</head>
<body>
<center>
top

for x in peanuts frank-and-ernest calvinandhobbes; do
echo fetching $x...
echo "<p><img src=$(wget -qO- http://www.gocomics.com/$x/$y/$m/$d | \
grep 'data-image=' | cut -d '"' -f 2).gif>" >> $f;
done

cat <<bottom >>$f
</center>
</body>
</html>
bottom

# unix-like...
# $BROWSER $f

# windows/busybox...
# cmd /c start $f

<<favs
andycapp
bc
calvinandhobbes
frank-and-ernest
garfield
heathcliff
marmaduke
peanuts
ripleysbelieveitornot
shoe
the-born-loser
wizardofid
favs

# eof

--
later on,
Mike

https://busybox.hypermart.net

Janis Papanagnou

unread,
Jan 14, 2018, 11:55:23 AM1/14/18
to
On 14.01.2018 16:51, Mike Sanders wrote:
> #!/bin/sh
[...]
> d=$(date +%d)
> m=$(date +%m)
> y=$(date +%Y)

Note that you may get wrong "d,m,y"-dates at certain instances of time
if you separate that logic in three independent calls of date.

Janis

> [...]

Lew Pitcher

unread,
Jan 14, 2018, 12:00:21 PM1/14/18
to
A possible fix....
RUNDATE=( $(date '+%d %m %Y' ) )
d=${RUNDATE[0]}
m=${RUNDATE[1]}
y=${RUNDATE[0]}


--
Lew Pitcher
"In Skills, We Trust"
PGP public key available upon request

Janis Papanagnou

unread,
Jan 14, 2018, 12:25:48 PM1/14/18
to
On 14.01.2018 18:00, Lew Pitcher wrote:
> Janis Papanagnou wrote:
>
>> On 14.01.2018 16:51, Mike Sanders wrote:
>>> #!/bin/sh
>> [...]
>>> d=$(date +%d)
>>> m=$(date +%m)
>>> y=$(date +%Y)
>>
>> Note that you may get wrong "d,m,y"-dates at certain instances of time
>> if you separate that logic in three independent calls of date.
>
> A possible fix....
> RUNDATE=( $(date '+%d %m %Y' ) )
> d=${RUNDATE[0]}
> m=${RUNDATE[1]}
> y=${RUNDATE[0]}

Or, if you don't have shell arrays, the more concise and classical

eval $( date '+d=%d m=%m y=%Y' )


Janis

Allodoxaphobia

unread,
Jan 14, 2018, 1:30:05 PM1/14/18
to
On Sun, 14 Jan 2018 15:51:59 +0000 (UTC), Mike Sanders wrote:
> #!/bin/sh

<-- snip -->
>
> for x in peanuts frank-and-ernest calvinandhobbes; do
> echo fetching $x...
> echo "<p><img src=$(wget -qO- http://www.gocomics.com/$x/$y/$m/$d | \
> grep 'data-image=' | cut -d '"' -f 2).gif>" >> $f;
> done

Actually, I find using *https* in the above _also_ WFM.

Jonesy
--
Marvin L Jones | Marvin | W3DHJ.net | linux
38.238N 104.547W | @ jonz.net | Jonesy | FreeBSD
* Killfiling google & XXXXbanter.com: jonz.net/ng.htm

Lew Pitcher

unread,
Jan 14, 2018, 2:27:47 PM1/14/18
to
Janis Papanagnou wrote:

> eval $( date '+d=%d m=%m y=%Y' )

Now, why didn't /I/ think of that?

Thanks, Janis. I've learned something new.

Kenny McCormack

unread,
Jan 14, 2018, 2:59:59 PM1/14/18
to
In article <p3gavd$5rp$1...@dont-email.me>,
Lew Pitcher <lew.p...@digitalfreehold.ca> wrote:
>Janis Papanagnou wrote:
>
>> eval $( date '+d=%d m=%m y=%Y' )
>
>Now, why didn't /I/ think of that?
>
>Thanks, Janis. I've learned something new.

Me, too. I didn't know you could do multiple variable assignments on a
single line like that.

--
Note that Oprah actually is all the things that The Donald only wishes he were.
For one thing, she actually *is* a billionaire. She's also actually self-made,
came from nothing, knows how to run businesses, never went bankrupt, is smart
and is mentally stable.

Mike Sanders

unread,
Jan 14, 2018, 3:57:09 PM1/14/18
to
Janis Papanagnou <janis_pa...@hotmail.com> wrote:

>> d=$(date +%d)
>> m=$(date +%m)
>> y=$(date +%Y)
>
> Note that you may get wrong "d,m,y"-dates at certain instances of time
> if you separate that logic in three independent calls of date.

Hi Janis. You know... that's a realy good point in fact.
Must mull this over.

Mike Sanders

unread,
Jan 14, 2018, 3:58:35 PM1/14/18
to
Allodoxaphobia <knock_you...@example.net> wrote:

>> for x in peanuts frank-and-ernest calvinandhobbes; do
>> echo fetching $x...
>> echo "<p><img src=$(wget -qO- http://www.gocomics.com/$x/$y/$m/$d | \
>> grep 'data-image=' | cut -d '"' -f 2).gif>" >> $f;
>> done
>
> Actually, I find using *https* in the above _also_ WFM.

Noted, many thanks Jonsey.

Mike Sanders

unread,
Jan 14, 2018, 4:50:38 PM1/14/18
to
Janis Papanagnou <janis_pa...@hotmail.com> wrote:

> Note that you may get wrong "d,m,y"-dates at certain instances of time
> if you separate that logic in three independent calls of date.

fixed...

v=$(date '+%Y%m%d')
y=${v:0:4}
m=${v:4:2}
d=${v:6}

while read x; do
echo $x | grep -q '^#' && continue
echo http://example/$x/$y/$m/$d/foo
done <<!
this
that
another
#ignored...
# yes read trims leading/trailing whitespace...
!

Allodoxaphobia

unread,
Jan 14, 2018, 6:17:40 PM1/14/18
to
On Sun, 14 Jan 2018 20:58:32 +0000 (UTC), Mike Sanders wrote:
> Allodoxaphobia <knock_you...@example.net> wrote:
>
>>> for x in peanuts frank-and-ernest calvinandhobbes; do
>>> echo fetching $x...
>>> echo "<p><img src=$(wget -qO- http://www.gocomics.com/$x/$y/$m/$d | \
>>> grep 'data-image=' | cut -d '"' -f 2).gif>" >> $f;
>>> done
>>
>> Actually, I find using *https* in the above _also_ WFM.
>
> Noted, many thanks Jonsey.

OH, Just GREAT!!, Mike!
Now I'll burn up hours upon hours geeking this thing out!

I added an <hr> to separate the comics somewhat.

I've already thought of

* Making the http://validator.w3.org/check happy

* Using cron to drop a fresh copy in my web site every 24 hours,
and to move existig copies to funnies-1.html , funnies-2.html ,
etc. so that I can catch up if travelling.

* Adding links at the top to load those previous days' pages.

* Using CSS to thicken the <hr> and to make the background
"newspaper greyish".

* Adding
<meta name="viewport" content="width=device-width, initial-scale=1">
and CSS to make it "Mobile Friendly"

= and more, I'm sure ...


OH, Just GREAT!!, Mike! See what'cha've done?

Really: SINCERE THANKS!

Chris Elvidge

unread,
Jan 14, 2018, 6:45:21 PM1/14/18
to
Why not do: ymd=$(date +"%Y/%m/%d")
And then use $ymd instead of $y/$m/$d


--

Chris Elvidge, England

Chris Elvidge

unread,
Jan 14, 2018, 7:05:48 PM1/14/18
to
On 14/01/2018 11:17 pm, Allodoxaphobia wrote:
> * Using cron to drop a fresh copy in my web site every 24 hours,
> and to move existig copies to funnies-1.html , funnies-2.html ,
> etc. so that I can catch up if travelling.

I put an RSS feed onto my website, changing daily

I can put the script here if you want
Cheers


--

Chris Elvidge, England

Mike Sanders

unread,
Jan 14, 2018, 7:11:19 PM1/14/18
to
Allodoxaphobia <knock_you...@example.net> wrote:

> OH, Just GREAT!!, Mike!
> Now I'll burn up hours upon hours geeking this thing out!
>
> I added an <hr> to separate the comics somewhat.
>
> I've already thought of
>
> * Making the http://validator.w3.org/check happy
>
> * Using cron to drop a fresh copy in my web site every 24 hours,
> and to move existig copies to funnies-1.html , funnies-2.html ,
> etc. so that I can catch up if travelling.
>
> * Adding links at the top to load those previous days' pages.
>
> * Using CSS to thicken the <hr> and to make the background
> "newspaper greyish".
>
> * Adding
> <meta name="viewport" content="width=device-width, initial-scale=1">
> and CSS to make it "Mobile Friendly"
>
> = and more, I'm sure ...
>
>
> OH, Just GREAT!!, Mike! See what'cha've done?

All really good ideas in fact - go for it Jonesy.

Here I'm thinking thumbnailed divs which
would afford an at-a-glance view, sorta like
an actual newspaper no? But yeah, a good
dose of CSS is just what the dr. ordered imo...

An aside... I notice that those published
on sunday, just as in real life, are larger,
so your check you work again on a week day
just to be safe.


> Really: SINCERE THANKS!

You're very welcome & if you decide to extend it,
I'll be happy to link to your script here:

<https://busybox.hypermart.net/funnies.html>

Have fun =)

Mike Sanders

unread,
Jan 14, 2018, 7:19:56 PM1/14/18
to
Chris Elvidge <ch...@mshome.net> wrote:

> Why not do: ymd=$(date +"%Y/%m/%d")
> And then use $ymd instead of $y/$m/$d

Thought of that as well Chris. It the most
straight forward way. Just one string...

Janis Papanagnou

unread,
Jan 14, 2018, 8:05:20 PM1/14/18
to
If the OP would want to use the variables not only in a path context
then you'd need the components. I haven't inspected the OP's code but
I think composing a part of the path is a special case that I'd rather
avoid given that shell programs often evolve. YMMV, of course.

Janis

Thomas 'PointedEars' Lahn

unread,
Jan 14, 2018, 11:30:36 PM1/14/18
to
Mike Sanders wrote:

> Chris Elvidge <ch...@mshome.net> wrote:
>> Why not do: ymd=$(date +"%Y/%m/%d")
>> And then use $ymd instead of $y/$m/$d
>
> Thought of that as well Chris. It the most
> straight forward way. Just one string...
^^^^^^^^^^^^^^^^ one word

It is also the most compatible way. “( … )” right-hand side requires
support for arrays, and POSIX-compliant shells do not need to have it.

BTW, “%Y/%m/%d” is an ill-advised date format as its interpretation depends
on the country of the user:

<https://en.wikipedia.org/wiki/Calendar_date#Usage_overloading>

In a potentially international setting such as a Web site, use ISO 8601
instead: “%Y-%m-%d”. Or use the current locale’s date format in the first
place: “%x” (not suitable for a dynamically generated HTML document).

<http://pubs.opengroup.org/onlinepubs/9699919799/utilities/date.html>

Finally, I do not think there is an inherent need to quote these format
strings.

--
PointedEars

Twitter: @PointedEars2
Please do not cc me. /Bitte keine Kopien per E-Mail.

Thomas 'PointedEars' Lahn

unread,
Jan 14, 2018, 11:35:22 PM1/14/18
to
Mike Sanders wrote:

> Janis Papanagnou <janis_pa...@hotmail.com> wrote:
>> Note that you may get wrong "d,m,y"-dates at certain instances of time
>> if you separate that logic in three independent calls of date.
>
> fixed...
>
> v=$(date '+%Y%m%d')
> y=${v:0:4}
> m=${v:4:2}
> d=${v:6}

That is even less compatible than “( … )” right-hand side:

<http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02>

Declare #!/bin/sh and use ShellCheck next time.

Chris Elvidge

unread,
Jan 15, 2018, 5:48:59 AM1/15/18
to
On 15/01/2018 04:30 am, Thomas 'PointedEars' Lahn wrote:
> BTW, “%Y/%m/%d” is an ill-advised date format as its interpretation depends
> on the country of the user:

Ah but the comics pages seem to us this (yyyy/mm/mm) format to index
their pages
viz: http://www.gocomics.com/nonsequitur/2018/01/14


--

Chris Elvidge, England

Mike Sanders

unread,
Jan 15, 2018, 8:31:42 AM1/15/18
to
Thomas 'PointedEars' Lahn <Point...@web.de> wrote:

> ...POSIX-compliant shells...

Have not & will not worry POSIX.
The end user has the source &
is presumably cognizant enough
to help themselves. If one asks,
needing help, by all means, I'll
always try. Elsewise (one word),
I'll be reading a good book as
life is to short to worry about
these sorts of things...

Kenny McCormack

unread,
Jan 15, 2018, 11:55:55 AM1/15/18
to
In article <p3i0ul$p3g$1...@dont-email.me>,
The pointy one would never let actual project requirements get in the way
of his philosophical demands on people's coding habits.

--
Trump has normalized hate.

The media has normalized Trump.

Thomas 'PointedEars' Lahn

unread,
Jan 15, 2018, 3:12:21 PM1/15/18
to
Mike Sanders wrote:

> Thomas 'PointedEars' Lahn <Point...@web.de> wrote:
>> ...POSIX-compliant shells...
>
> Have not & will not worry POSIX.

If you declare “#!/bin/sh” as you did, then you SHOULD worry about it.
There is nothing wrong per se with using shell-specific syntax, but that
you SHOULD declare the corresponding shell.

> The end user has the source &
> is presumably cognizant enough
> to help themselves. If one asks,
> needing help, by all means, I'll
> always try. Elsewise (one word),
> I'll be reading a good book as
> life is to short to worry about
> these sorts of things...

If you want people to NOT use your code, that is the right attitude.

Thomas 'PointedEars' Lahn

unread,
Jan 15, 2018, 3:14:48 PM1/15/18
to
ACK. But that does not mean that you should use it in *output*, like
the “title” element, too.

Thomas 'PointedEars' Lahn

unread,
Jan 15, 2018, 3:16:33 PM1/15/18
to
Kenny McCormack wrote:

> In article <p3i0ul$p3g$1...@dont-email.me>,
> Chris Elvidge <ch...@mshome.net> wrote:
>>On 15/01/2018 04:30 am, Thomas 'PointedEars' Lahn wrote:
>>> BTW, “%Y/%m/%d” is an ill-advised date format as its
>>> interpretation depends on the country of the user:
>>
>>Ah but the comics pages seem to us this (yyyy/mm/mm) format to index
>>their pages
>>viz: http://www.gocomics.com/nonsequitur/2018/01/14
>
> The pointy one would never let actual project requirements get in the way
> of his philosophical demands on people's coding habits.

Such comments as yours merely demonstrate incompetence.

Thomas 'PointedEars' Lahn

unread,
Jan 15, 2018, 3:18:23 PM1/15/18
to
Mike Sanders wrote:

> Thomas 'PointedEars' Lahn <Point...@web.de> wrote:
>> ...POSIX-compliant shells...
>
> Have not & will not worry POSIX.

If you declare “#!/bin/sh” as you did, then you SHOULD worry about it.
There is nothing wrong per se with using shell-specific syntax, but then
you SHOULD declare the corresponding shell.

> The end user has the source &
> is presumably cognizant enough
> to help themselves. If one asks,
> needing help, by all means, I'll
> always try. Elsewise (one word),
> I'll be reading a good book as
> life is to short to worry about
> these sorts of things...

“Guess my shell” is the right attitude if you want people to NOT use your
code.

Mike Sanders

unread,
Jan 15, 2018, 6:21:42 PM1/15/18
to
Thomas 'PointedEars' Lahn <Point...@web.de> wrote:

> ?Guess my shell?...

Well, thank you for your input Thomas, I appreciate it.
This however is just a simple script representing a
discovery about the directory hierarchy that hosts
the image URLs. Nothing serious, more like 'hey nifty,
guys come see what I've found'. Just for fun thats all.
If you wish to contribute a fully POSIX version to
demonstrate your points, then I'll read & study it...

Thomas 'PointedEars' Lahn

unread,
Jan 15, 2018, 7:54:09 PM1/15/18
to
Mike Sanders wrote:

> Thomas 'PointedEars' Lahn <Point...@web.de> wrote:
>> ?Guess my shell?...
>
> Well, thank you for your input Thomas, I appreciate it.
> This however is just a simple script representing a
> discovery about the directory hierarchy that hosts
> the image URLs. Nothing serious, more like 'hey nifty,
> guys come see what I've found'. Just for fun thats all.
> If you wish to contribute a fully POSIX version to
> demonstrate your points, then I'll read & study it...

You must be kidding. Do your own homework.

Also, I have already told you what to do and why.

But apparently I have not made myself clear:

The shebang “#!…” at the beginning of a text file is NOT just a single-line
comment, NOT just a hint (to a syntax-highlighter and syntax checker;
although it helps with Vim and ShellCheck). It specifies THE PATH OF THE
PROGRAM THAT WILL BE USED to execute the file if it is the invocation name:

<https://en.wikipedia.org/wiki/Shebang_(Unix)>

As a result, your code with the updates in <news:p3g2b0$vjh$1...@dont-email.me>
or <news:p3gjb8$os9$1...@news.albasani.net> DOES NOT EXECUTE unless /bin/sh is
symlinked to a shell that supports “${…:…:…}”, such as /bin/bash, because it
is SYNTACTICALLY INCORRECT.

/bin/sh is the path of THE DEFAULT SYSTEM SHELL; it is supposed to be, or be
symlinked to, a FULLY POSIX-COMPLIANT SHELL, such as /bin/dash (in the past
it was supposed to be the original Bourne Shell, but those days are gone).

And then:

------------------------------ Bite here -----------------------------

$ cat > funnies.sh
#!/bin/sh

<<about
funnies.sh - 2018 Michael Sanders
creates a webpage of 'funnies'
beware wordwrap & enjoy =)
about

f=funnies.html
y=${v:0:4}
m=${v:4:2}
d=${v:6}

cat <<top >$f
<html>
<head>
<title>funnies: $y/$m/$d</title>
</head>
<body>
<center>
top

for x in peanuts frank-and-ernest calvinandhobbes; do
echo fetching $x...
echo "<p><img src=$(wget -qO- http://www.gocomics.com/$x/$y/$m/$d | \
grep 'data-image=' | cut -d '"' -f 2).gif>" >> $f;
done

cat <<bottom >>$f
</center>
</body>
</html>
bottom

# unix-like...
# $BROWSER $f

# windows/busybox...
# cmd /c start $f

<<favs
andycapp
bc
calvinandhobbes
frank-and-ernest
garfield
heathcliff
marmaduke
peanuts
ripleysbelieveitornot
shoe
the-born-loser
wizardofid
favs

# eof
^D

$ chmod +x funnies.sh

$ ./funnies.sh
./funnies.sh: 10: ./funnies.sh: Bad substitution

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Jan 16 01:42 ‘/bin/sh’ -> ‘dash’

------------------------------ Bite here -----------------------------

This is line 10:

y=${v:0:4}

So if you wish to DISTRIBUTE your script, and you indicated at least in
<news:p3grj4$63i$1...@news.albasani.net> that you do, you leave your users
(and yourself) GUESSING what your system shell was when you wrote the
script.

And it is possible to use shell-specific features such that the script does
run with another shell, but does something unexpected; it might even wreak
havoc on the user’s system.

To distribute such junk code is not only incompetent, it is irresponsible.
Industry standards exist for a reason. If you do not want to limit yourself
to the standards, you MUST DECLARE it by THE PROPER SHEBANG.


Also, your newsreader is b0rked: There were no question marks in my text.

Mike Sanders

unread,
Jan 16, 2018, 7:15:01 AM1/16/18
to
Thomas 'PointedEars' Lahn <Point...@web.de> wrote:

> This is line 10:
>
> y=${v:0:4}

No no, see:

<https://busybox.hypermart.net/funnies.html>

> I have already told you what to do and why.

Thomas, as gently as I can muster... I don't
give a rat's ass that you've 'already told me
what to do and why', you see:

I am not seeking permission - I assume it.

> ...you MUST...

Non-sense... I need not do anyhing. I understand
that you as officating grand poobah of the order
of POSIX weenies will have a cow, (hell, have two
if you wish). But as for me, I'm not worried about
it. Instead, I'm having lots of fun watching you
freak out:

<https://busybox.hypermart.net/media/popcorn.gif>

Have a good day =)

Kenny McCormack

unread,
Jan 16, 2018, 8:24:41 AM1/16/18
to
In article <p3kqbv$lob$1...@news.albasani.net>,
Mike Sanders <mi...@porkchop.bsd> wrote:
>Thomas 'PointedEars' Lahn <Point...@web.de> wrote:
>
>> This is line 10:
>>
>> y=${v:0:4}
>
>No no, see:
> (URL: https://busybox.hypermart.net/funnies.html)

Looking at that briefly, it looks like you went with the simpler:

d=$(date +%Y/%m/%d)

and dispensed with the idea of calculating individual y, m, and d.

So, the whole issue of this thread is now moot.

>
>> I have already told you what to do and why.
>
>Thomas, as gently as I can muster... I don't
>give a rat's ass that you've 'already told me
>what to do and why', you see:
>
>I am not seeking permission - I assume it.
>
>> ...you MUST...

The pointy one is an A-hole. That's not even a topic of discussion.
His bombastic, ridiculous, and utterly pointless posting style is the
reason hs is in my (and most others') killfile(s).

But, for all that, he is basically right here. Which is that if you are
going to use bash-specific features (like the y=${v:0:4} substring
notation), then you should put /bin/bash as the shebang line. In fact, I
always start any shell script I write with #!/bin/bash and just be done
with it. Why write for earlier, crippled shells?

Note that, contrary to what the pointy one says, even if /bin/sh *is* a
symlink to /bin/bash, it still (on many/most, but not all, systems) will
behave as the earlier, crippled shell if invoked as /bin/sh.

So, the bottom line is there really is no reason to use #!/bin/sh at all.
Just use #!/bin/bash and be done with it.

Not, of course, that any of this adds up to a hill of beans in any case.
Everyone should do as they like and, as they say in the movies, lighten up,
Francis!

--
(Cruz certainly has an odd face) ... it looks like someone sewed pieces of a
waterlogged Reagan mask together at gunpoint ...

http://www.rollingstone.com/politics/news/how-america-made-donald-trump-unstoppable-20160224

Mike Sanders

unread,
Jan 16, 2018, 8:58:15 AM1/16/18
to
All correct of course Kenny (not to mention your unerring ability
to swoop & give a heads up, darn man, you're good, I kid you not).

The one thing I seem to have problems with is the um, nuance used
to convey the message...

But back to lurking for me. Waiting on a project from you to emerge
too btw, you've usually got something cooking.

Thomas 'PointedEars' Lahn

unread,
Jan 16, 2018, 10:31:38 AM1/16/18
to
Mike Sanders wrote:

> Thomas 'PointedEars' Lahn <Point...@web.de> wrote:
>> This is line 10:
>>
>> y=${v:0:4}
>
> No no, see:
>
> <https://busybox.hypermart.net/funnies.html>

$ echo $0
-/bin/bash

$ x=(foo bar)

$ ln -s /bin/busybox sh

$ ./sh

BusyBox v1.22.1 (Debian 1:1.22.0-19) built-in shell (ash)
Enter 'help' for a list of built-in commands.

$ x=(foo bar)

$ x=(foo bar)
./sh: syntax error: unexpected "("

Nuff said.

>> I have already told you what to do and why.
>
> Thomas, as gently as I can muster... I don't
> give a rat's ass that you've 'already told me
> what to do and why', you see:
>
> I am not seeking permission - I assume it. [fallacies]

Pearls before the swine. Score adjusted.

Thomas 'PointedEars' Lahn

unread,
Jan 16, 2018, 10:32:29 AM1/16/18
to
Mike Sanders wrote:

> Thomas 'PointedEars' Lahn <Point...@web.de> wrote:
>> This is line 10:
>>
>> y=${v:0:4}
>
> No no, see:
>
> <https://busybox.hypermart.net/funnies.html>

$ echo $0
-/bin/bash

$ x=(foo bar)

$ ln -s /bin/busybox sh

$ ./sh

BusyBox v1.22.1 (Debian 1:1.22.0-19) built-in shell (ash)
Enter 'help' for a list of built-in commands.

$ x=(foo bar)
./sh: syntax error: unexpected "("

Nuff said.

>> I have already told you what to do and why.
>
> Thomas, as gently as I can muster... I don't
> give a rat's ass that you've 'already told me
> what to do and why', you see:
>
> I am not seeking permission - I assume it. [fallacies]

Pearls before the swine. Score adjusted.

Mike Sanders

unread,
Jan 16, 2018, 11:04:18 AM1/16/18
to
Thomas 'PointedEars' Lahn <Point...@web.de> wrote:
^
| you've changed it,
yet said my terminal
had issues, hmm...

> Pearls before the swine.

Reckon?

Look: I understand your preference for (& the importance of)
POSIX Thomas & that's a good thing. But you seem to lie in
wait for schadenfreude with your bad attitude, so unless you
can hold your mouth still & be more neighborly, it will be...

plonk!

Ivan Shmakov

unread,
Jan 16, 2018, 12:45:46 PM1/16/18
to
>>>>> Mike Sanders <mi...@porkchop.bsd> writes:
>>>>> Janis Papanagnou <janis_pa...@hotmail.com> wrote:

>> Note that you may get wrong "d,m,y"-dates at certain instances of
>> time if you separate that logic in three independent calls of date.

> fixed...

> v=$(date '+%Y%m%d') ; y=${v:0:4} ; m=${v:4:2} ; d=${v:6}

Speaking of which. I'm not generally shy of using Bash
extensions (<() process substitution first and foremost, but
also arrays, ${varn/what/with} substitution, etc.), yet in
one of the programs I've coded recently I saw no much need
for them, and decided to aim for POSIX compatibility instead.
(Even though said program is specific to Linux LVM anyway.)

Hence, I've come up with the following.

nth () {
shift "$1"
## .
test "$#" -ge 2 \
&& printf %s\\n "$2"
}

Which allows for, e. g.:

v=$(date +"%Y %m %d") ; y=$(nth 1 ${v}) ; m=$(nth 2 ${v}) ; d=$(nth 3 ${v})

Does that look sensible, or is there a better solution?

[...]

--
FSF associate member #7257 http://am-1.org/~ivan/

Janis Papanagnou

unread,
Jan 16, 2018, 1:04:54 PM1/16/18
to
On 16.01.2018 18:45, Ivan Shmakov wrote:
>>>>>> Mike Sanders <mi...@porkchop.bsd> writes:
>>>>>> Janis Papanagnou <janis_pa...@hotmail.com> wrote:
>
> >> Note that you may get wrong "d,m,y"-dates at certain instances of
> >> time if you separate that logic in three independent calls of date.
>
> > fixed...
>
> > v=$(date '+%Y%m%d') ; y=${v:0:4} ; m=${v:4:2} ; d=${v:6}
>
> Speaking of which. I'm not generally shy of using Bash
> extensions (<() process substitution first and foremost, but
> also arrays, ${varn/what/with} substitution, etc.), yet in

Nowadays it's not that often necessary any more to restrict oneself, but
a POSIX solution is certainly usable in more contexts than using shell
specific extensions. It certainly depends on your application context.

Specifically your list of sensible features (which I think stem mostly or
even completely from Ksh) have been adopted by common and widely used
shells (like Bash), which makes restricting to POSIX necessary in even
less cases.

I would abstain, though, or at least ponder about it, if you intend using
shell-proprietary features.

> one of the programs I've coded recently I saw no much need
> for them, and decided to aim for POSIX compatibility instead.
> (Even though said program is specific to Linux LVM anyway.)
>
> Hence, I've come up with the following.
>
> nth () {
> shift "$1"
> ## .
> test "$#" -ge 2 \
> && printf %s\\n "$2"
> }
>
> Which allows for, e. g.:
>
> v=$(date +"%Y %m %d") ; y=$(nth 1 ${v}) ; m=$(nth 2 ${v}) ; d=$(nth 3 ${v})
>
> Does that look sensible, or is there a better solution?

Overly complicated and bulky, even if restricting to POSIX, IMO. Have you
seen the simple eval based proposal upthread?

FYC: eval $( date '+d=%d m=%m y=%Y' )


Janis

>
> [...]
>

Ivan Shmakov

unread,
Jan 16, 2018, 1:20:47 PM1/16/18
to
>>>>> Janis Papanagnou <janis_pa...@hotmail.com> writes:

[...]

>> and decided to aim for POSIX compatibility instead. (Even though
>> said program is specific to Linux LVM anyway.)

>> Hence, I've come up with the following.

>> nth () {
>> shift "$1"
>> ## .
>> test "$#" -ge 2 \
>> && printf %s\\n "$2"
>> }

>> Which allows for, e. g.:

>> v=$(date +"%Y %m %d") ; y=$(nth 1 ${v}) ; m=$(nth 2 ${v}) ; d=$(nth 3 ${v})

>> Does that look sensible, or is there a better solution?

> Overly complicated and bulky, even if restricting to POSIX, IMO.

How so?

> Have you seen the simple eval based proposal upthread?

> FYC: eval $( date '+d=%d m=%m y=%Y' )

Well, what I /am/ shy of is using eval. (Consider, for
instance, that the program called misformats the output due to a
bug; that in turn could lead to literally any behavior in the
calling code, thus possibly being quite a hassle to troubleshoot.)

Besides, nth as defined above can help parsing output of a
program even if it isn't as customizable as that of date(1).
(Not exactly my case, but still.)

Mike Sanders

unread,
Jan 16, 2018, 1:34:27 PM1/16/18
to
Ivan Shmakov <iv...@siamics.net.remove.invalid> wrote:

> nth () {
> shift "$1"
> ## .
> test "$#" -ge 2 \
> && printf %s\\n "$2"
> }
>
> Which allows for, e. g.:
>
> v=$(date +"%Y %m %d") ; y=$(nth 1 ${v}) ; m=$(nth 2 ${v}) ; d=$(nth 3 ${v})
>
> Does that look sensible, or is there a better solution?


Ivan, while I've already settled on a solution:

<https://busybox.hypermart.net/funnies.html>

I do like your thinking, it almost has a 'dynamic case...esac'
or even lisp-like approach in a way. This could be expanded
for other uses...

In this particular case, for assigning multiple variables in
a single pass though, Janis's eval approach wins, no contest...
well, it could be misused I guess, but still that little gem
(& few others she's cooked up too) went into my notes.

At any rate, thank you for suggestions, I do appreciate it &
by all means, keep brain-storming, lots of good reading seeing
where you took the idea.

Janis Papanagnou

unread,
Jan 16, 2018, 2:07:43 PM1/16/18
to
On 16.01.2018 19:20, Ivan Shmakov wrote:
[...]
>
> > Overly complicated and bulky, even if restricting to POSIX, IMO.
>
> How so?

Is this a serious question? - Just count your lines, compare your bulky
classic constructs with many of the proposed simple ones in this thread,
count the number of involved commands, consider in how many places you
can spoil your code, etc. - You were the one who asked "Does that look
sensible, or is there a better solution?" - The answer is quite obvious,
I'd say, isn't it?

>
> > Have you seen the simple eval based proposal upthread?
>
> > FYC: eval $( date '+d=%d m=%m y=%Y' )
>
> Well, what I /am/ shy of is using eval.

That's certainly your subjective problem, not a problem using eval in
this context.

Eval can become a problem in cases where you process (for example)
uninterpreted and untested user input. But that is irrelevant here;
above construct is absolutely safe. (If you have another opinion on
that you may want to elaborate on a concrete and realistic example.
Your shyness isn't a cateegory we can discuss on. A bug in system
tools isn't as well, more so in context of your own bulky proposal.)

(Still wondering whether you are serious with your question in the
first place. It just sounds too strange.)

Janis

> [ snip ]

Mike Sanders

unread,
Jan 16, 2018, 2:24:10 PM1/16/18
to
Janis Papanagnou <janis_pa...@hotmail.com> wrote:

> Is this a serious question?

c'mon - yes it was Janis. He posted an idea
that could lead to other ideas:

new idea
/
janis | tee
/ \
mike | tee ???
\
ivan | tee
\
new idea


instead we have:

ivan --ideas nth | janis > /dev/null


Let him offer up ideas just as you did.

Why is it so hard for everyone...

Ivan ignore those who say you cant think aloud - just do it.

Janis Papanagnou

unread,
Jan 16, 2018, 7:48:06 PM1/16/18
to
On 16.01.2018 20:24, Mike Sanders wrote:
> Janis Papanagnou <janis_pa...@hotmail.com> wrote:
>
>> Is this a serious question?
>
> c'mon - yes it was Janis. He posted an idea
> that could lead to other ideas:

Hey, don't get me wrong; there's nothing wrong in posting new ideas.

But for the given case there was a sensible answer necessary to his
question: "Does that look sensible, or is there a better solution?".
And for the given case the answer is quite obviously: Yes, there are
a lot of much better solutions (and for various reasons, but some of
them only in defined contexts - legacy, POSIX, common, proprietary).

Since you seem to not focus on POSIX there's really a lot ideas how
to tackle the split of date and avoid multiple calls. For me, being
primarily a Ksh user, this one (for example) may be preferable since
[in Ksh] it doesn't require any external command, and not even date:

printf "%(%Y %m %d)T" | read y m d

To extract parts of an argument list you could use in modern shells
(Ksh, Bash, Zsh) for example (non-standard) ${@:n:1} (and related
variants) instead of a POSIX compatible but bulky "n-th" function.
Even using standard awk for such tasks (awk '{print $N}') seems much
clearer (though certainly less performant).

Ivan can propose what he likes, and he can "think aloud" of course;
no one will effectively prevent him. Anyone who speeks aloud should
not have problems getting an echo to his speech. Specifically so if
the poster even asked for a comment.

As you seem to like and support posting of many ideas I suggest to
also accept criticism on obviously inferior code. The readers shall
be informed as best as possible and be able to judge themselves and
choose their own preferred way.

Spreaded FUD ("eval") or "shyness" using safe constructs certainly
demands a rebuttal to not misguide the uninformed readers.

Now let's look into the "OT" part of Ivan's post; the introduction
of an "nth" function. It would be advantageous if we had that in an
own thread, so that we could discuss it; e.g. all the bugs and the
deficiencies these few lines of code actually have - left as an
exercise to the reader even if they are quite obvious! -, a quality
which can also be seen as a result of the code's bulkiness.

Janis

Ivan Shmakov

unread,
Jan 16, 2018, 8:50:35 PM1/16/18
to
>>>>> Janis Papanagnou <janis_pa...@hotmail.com> writes:
>>>>> On 16.01.2018 19:20, Ivan Shmakov wrote:

>>> Overly complicated and bulky, even if restricting to POSIX, IMO.

>> How so?

> Is this a serious question? - Just count your lines,

The code can be fit on one 80-characters line if so desired.

nth () { shift "$1" ; test "$#" -ge 2 && printf %s\\n "$2" ; }

> compare your bulky classic constructs with many of the proposed
> simple ones in this thread, count the number of involved commands,

Just three. And while only one of them is required to be a
builtin, in practice they all will be more often than not.

> consider in how many places you can spoil your code, etc. - You were
> the one who asked "Does that look sensible, or is there a better
> solution?" - The answer is quite obvious, I'd say, isn't it?

For the general case of a command that emits whitespace-separated
parcels of data? (Or, actually, separated by any octet, thanks
to IFS.) To me, it isn't quite so obvious. Even less so if
those parcels are not guaranteed to be free of Shell special
characters, such as $ or (.

>>> Have you seen the simple eval based proposal upthread?

>>> FYC: eval $( date '+d=%d m=%m y=%Y' )

>> Well, what I /am/ shy of is using eval.

> That's certainly your subjective problem, not a problem using eval in
> this context.

In a way. But I don't suppose you're willing to maintain my
code, right? Hence I daresay that developer's subjective
problems can and in fact /do/ matter for one's coding.

> Eval can become a problem in cases where you process (for example)
> uninterpreted and untested user input. But that is irrelevant here;
> above construct is absolutely safe.

I see no reason to challenge the safety of date(1) to produce
eval-friendly key=value output in this specific case. (I would
be wary of accepting it were it to feature any locale-dependent
format sequence, though, as I'm not entirely sure that no locale
can possibly use Shell special characters in this context.)

[...]

Ben Bacarisse

unread,
Jan 16, 2018, 8:54:55 PM1/16/18
to
Janis Papanagnou <janis_pa...@hotmail.com> writes:
<snip>
> Since you seem to not focus on POSIX there's really a lot ideas how
> to tackle the split of date and avoid multiple calls.

I like to do this by calling a function. It works on POSIX shells and
you very often find it makes sense to hive-off a part of the work into a
function anyway. Here, I am doing but setting shell vars so the
function has no other purpose, but that would not normally be the case.

assign () { y="$1" m="$2" d="$3" ; }

assign $(date '+%Y %m %d')

<snip>
--
Ben.

Thomas 'PointedEars' Lahn

unread,
Jan 16, 2018, 11:19:26 PM1/16/18
to
Obvious in hindsight, but still nice.

--
PointedEars
<https://github.com/PointedEars> | <http://PointedEars.de/wsvn/>

Mike Sanders

unread,
Jan 17, 2018, 7:06:13 AM1/17/18
to
Janis Papanagnou <janis_pa...@hotmail.com> wrote:

> Hey, don't get me wrong; there's nothing wrong
> in posting new ideas.

Nice post. (Running behind so only short reply...)

> POSIX

Speaking only for myself: POSIX hates more than it likes.
Necessary? Probably, but beware the man of one book...
If someone one were to tell me (say) 'Perl is the one
true way' I'd then wonder but what about Python?

> printf "%(%Y %m %d)T" | read y m d

Ha! Good bit of code golf.

> I suggest to also accept criticism...

Yes. If the 1st law of rational discourse is that no
(earnest) idea is above criticism, then it follows,
the 2nd law must necessarily be that no (earnest) idea
is beneath consideration. This seems just to me at least.
Consider the term 'development', an idea has to develop,
this implies gestation or a few iterations to gel.

> Spreaded FUD ("eval")...

Not sure about this point... These are your thoughts. How
do you /know/ that was the OP's /intent/? There are valid
concerns about eval. Its probably best thought of as relative
if someone asked me.

> the "OT" part...

Well, I personally don't mind as it helps to annotate the
conversation. I am not a simulacrum Janis, I'm human.
'Words' are human code... They impart context. Not such
a transgression for me at least.

Well, off to work for me, thanks for slowing down &
taking the time to explain your thinking.

Mike Sanders

unread,
Jan 17, 2018, 7:37:48 AM1/17/18
to
Ben Bacarisse <ben.u...@bsb.me.uk> wrote:

> assign () { y="$1" m="$2" d="$3" ; }
>
> assign $(date '+%Y %m %d')

That's pretty good too.

Mike Sanders

unread,
Jan 17, 2018, 8:09:28 AM1/17/18
to
Janis Papanagnou <janis_pa...@hotmail.com> wrote:

> Even using standard awk....

# experimenting...

eval $( date '+m=%m y=%Y d=1' )

days=$( cal $m $y | awk 'NF {days = $NF}; END {print days}' )

while [ $d -le $days ]
do
echo fetch peanuts/$y/$m/$d
d=$(($d+1))
done

Ivan Shmakov

unread,
Jan 17, 2018, 8:57:42 AM1/17/18
to
>>>>> Ivan Shmakov <iv...@siamics.net.REMOVE.invalid> writes:

[...]

> Hence, I've come up with the following.

> nth () { shift "$1" ; test "$#" -ge 2 && printf %s\\n "$2" ; }

> Which allows for, e. g.:

> v=$(date +"%Y %m %d") ; y=$(nth 1 ${v}) ; m=$(nth 2 ${v}) ; d=$(nth 3 ${v})

> Does that look sensible, or is there a better solution?

... And then it dawned on me: "that" is to blame! Namely,
by "that" in the above I meant the nth function first and
foremost, /not/ the part after "e. g."

Apologies for not making myself clear.

That said, I'm still interested in what other (better) ways are
there for parsing space (or any other ASCII character) delimited
strings emitted by commands called from Shell. (And thanks Ben
Bacarisse for showing one in news:87efmp4...@bsb.me.uk, BTW.)

Chris Elvidge

unread,
Jan 17, 2018, 11:07:11 AM1/17/18
to
On 14/01/2018 11:17 pm, Allodoxaphobia wrote:
> On Sun, 14 Jan 2018 20:58:32 +0000 (UTC), Mike Sanders wrote:
>> Allodoxaphobia <knock_you...@example.net> wrote:
>>
>>>> for x in peanuts frank-and-ernest calvinandhobbes; do
>>>> echo fetching $x...
>>>> echo "<p><img src=$(wget -qO- http://www.gocomics.com/$x/$y/$m/$d | \
>>>> grep 'data-image=' | cut -d '"' -f 2).gif>" >> $f;
>>>> done
>>>
>>> Actually, I find using *https* in the above _also_ WFM.
>>
>> Noted, many thanks Jonsey.
>
> OH, Just GREAT!!, Mike!
> Now I'll burn up hours upon hours geeking this thing out!
>
> I added an <hr> to separate the comics somewhat.
>
> I've already thought of
>
> * Making the http://validator.w3.org/check happy
>
> * Using cron to drop a fresh copy in my web site every 24 hours,
> and to move existig copies to funnies-1.html , funnies-2.html ,
> etc. so that I can catch up if travelling.
>
> * Adding links at the top to load those previous days' pages.
>
> * Using CSS to thicken the <hr> and to make the background
> "newspaper greyish".
>
> * Adding
> <meta name="viewport" content="width=device-width, initial-scale=1">
> and CSS to make it "Mobile Friendly"
>
> = and more, I'm sure ...
>
>
> OH, Just GREAT!!, Mike! See what'cha've done?
>
> Really: SINCERE THANKS!
> Jonesy
>

To save hammering the server put a "sleep $((RANDOM%10))" line before
wgetting the data


--

Chris Elvidge, England

Kenny McCormack

unread,
Jan 17, 2018, 11:57:53 AM1/17/18
to
In article <p3ne7f$qom$1...@news.albasani.net>,
Mike Sanders <mi...@porkchop.bsd> wrote:
...
>> printf "%(%Y %m %d)T" | read y m d
>
>Ha! Good bit of code golf.

A couple of comments about this:

1) I never knew about this! But note that it isn't standard printf(1). It
seems to exist in bash (perhaps also in ksh, since that's what Janis uses).
It is not in /usr/bin/printf.
(Tested on a reasonably current Debian Linux system)

2) At least in bash (can't say about ksh), the above command won't work as
expected, because the "read" gets executed in a subshell. The variable
assignments won't be visisble in the calling shell script.

The usual workaround is to use a here-document like this:

$ read y m d << EOF
$(printf "%(%Y %m %d)T")
EOF
$ echo $y $m $d

Or, in bash, you can do:

$ read y m d <<< $(printf "%(%Y %m %d)T")
$ echo $y $m $d

--
The key difference between faith and science is that in science, evidence that
doesn't fit the theory tends to weaken the theory (that is, make it less likely to
be believed), whereas in faith, contrary evidence just makes faith stronger (on
the assumption that Satan is testing you - trying to make you abandon your faith).

Mike Sanders

unread,
Jan 17, 2018, 1:23:06 PM1/17/18
to
Kenny McCormack <gaz...@shell.xmission.com> wrote:

> A couple of comments about this:
>
> 1) I never knew about this! But note that it isn't standard printf(1). It
> seems to exist in bash (perhaps also in ksh, since that's what Janis uses).
> It is not in /usr/bin/printf.
> (Tested on a reasonably current Debian Linux system)
>
> 2) At least in bash (can't say about ksh), the above command won't work as
> expected, because the "read" gets executed in a subshell. The variable
> assignments won't be visisble in the calling shell script.
>
> The usual workaround is to use a here-document like this:
>
> $ read y m d << EOF
> $(printf "%(%Y %m %d)T")
> EOF
> $ echo $y $m $d
>
> Or, in bash, you can do:
>
> $ read y m d <<< $(printf "%(%Y %m %d)T")
> $ echo $y $m $d

ksh here in OpenBSD & b/ash in busybox under Windows
(wrote funnies.sh in busybox):

<https://frippery.org/busybox/>

OT but yeally nifty Kenny... A single EXE of only 400kb
gets you a tiny Unix substrate for running light shell
scripts under Windows at work (list at end of this post*),
sure enough beats Windows batch language... just type
'ls' or 'grep' only to have %comspec% (equals $SHELL)
spit out:

'grep' is not recognized as an internal or external
command, operable program or batch file.

Syntax under Windows coulde be any of:

'busybox bash'

'busybox sh -c script'

'busybox awk -vx=%1 -vy=%2 c:/path/to/script.awk'

* embedded busybox utilities:

[ [[ alias ar ash awk base64 basename bash break bunzip2
bzcat bzip2 cal cat catv cd chdir chmod cksum clear cmp
comm command continue cp cpio cut date dc dd df diff dirname
dos2unix dpkg-deb du echo ed egrep env eval exec exit expand
export expr false fgrep find fold ftpget ftpput getopt
getopts grep groups gunzip gzip hash hd head help hexdump
history id ipcalc kill killall less let ln local logname ls
lzcat lzma lzop lzopcat man md5sum mkdir mktemp mv nc od
patch pgrep pidof printenv printf ps pwd read readonly
return rev rm rmdir rpm2cpio sed seq set sh sha1sum sha256sum
sha3sum sha512sum shift shuf sleep sort source split stat
strings sum tac tail tar tee test times touch tr trap true
truncate type ulimit umask unalias uname uncompress unexpand
uniq unix2dos unlink unlzma unlzop unset unxz unzip usleep
uudecode uuencode vi wait wc wget which whoami whois xargs
xz xzcat yes zcat

marrgol

unread,
Jan 17, 2018, 2:08:45 PM1/17/18
to
On 2018-01-17 at 17:57, Kenny McCormack wrote:
> ...
>>> printf "%(%Y %m %d)T" | read y m d
> […]
> 2) At least in bash (can't say about ksh), the above command won't work as
> expected, because the "read" gets executed in a subshell. The variable
> assignments won't be visisble in the calling shell script.
>
> The usual workaround is to use a here-document like this:
>
> $ read y m d << EOF
> $(printf "%(%Y %m %d)T")
> EOF
> $ echo $y $m $d
>
> Or, in bash, you can do:
>
> $ read y m d <<< $(printf "%(%Y %m %d)T")
> $ echo $y $m $d

Another workaround in bash is to use process substitution:

$ read y m d < <(printf "%(%Y %m %d)T")


--
mrg

Kaz Kylheku

unread,
Jan 17, 2018, 2:18:02 PM1/17/18
to
On 2018-01-17, Kenny McCormack <gaz...@shell.xmission.com> wrote:
> In article <p3ne7f$qom$1...@news.albasani.net>,
> Mike Sanders <mi...@porkchop.bsd> wrote:
> ...
>>> printf "%(%Y %m %d)T" | read y m d
>>
>>Ha! Good bit of code golf.
>
> A couple of comments about this:
>
> 1) I never knew about this! But note that it isn't standard printf(1). It

It may have come up in this newsgroup before, in the not-too-distant
past. I seem to recall a discussion around a "mysterious" %s involved
in something like %(%s)T, or some such thing.

Jens Schweikhardt

unread,
Jan 17, 2018, 4:23:42 PM1/17/18
to
Mike Sanders <mi...@porkchop.bsd> wrote
in <p3ng2m$ldo$1...@news.albasani.net>:
# Ben Bacarisse <ben.u...@bsb.me.uk> wrote:
#
#> assign () { y="$1" m="$2" d="$3" ; }
#>
#> assign $(date '+%Y %m %d')
#
# That's pretty good too.

I'm late to this thread, so haven't seen everything that was proposed.
My take:

set $(date '+%Y %m %d')
y=$1 m=$2 d=$3

No eval. Pure POSIX. And since date(1) output in this case is all
digits, no need to worry about globbing messing up "set".


Regards,

Jens
--
Jens Schweikhardt http://www.schweikhardt.net/
SIGSIG -- signature too long (core dumped)

Mike Sanders

unread,
Jan 17, 2018, 4:57:55 PM1/17/18
to
Jens Schweikhardt <use...@schweikhardt.net> wrote:

> I'm late to this thread, so haven't seen everything that was proposed.

Hi Jens. No worries all ideas are welcome.

> My take:
>
> set $(date '+%Y %m %d')
> y=$1 m=$2 d=$3
>
> No eval. Pure POSIX. And since date(1) output in this case is all
> digits, no need to worry about globbing messing up "set".

I cant believe I didn't think of this... Simple really is beautiful!

Thomas 'PointedEars' Lahn

unread,
Jan 17, 2018, 8:26:54 PM1/17/18
to
Jens Schweikhardt wrote:

> Mike Sanders <mi...@porkchop.bsd> wrote
> in <p3ng2m$ldo$1...@news.albasani.net>:
> # Ben Bacarisse <ben.u...@bsb.me.uk> wrote:
> #
> #> assign () { y="$1" m="$2" d="$3" ; }
> #>
> #> assign $(date '+%Y %m %d')
> #
> # That's pretty good too.
>
> I'm late to this thread, so haven't seen everything that was proposed.
> My take:
>
> set $(date '+%Y %m %d')
> y=$1 m=$2 d=$3
>
> No eval. Pure POSIX. And since date(1) output in this case is all
> digits, no need to worry about globbing messing up "set".

The only problem with it is that it replaces *all* positional arguments;
so if they are important, they need to be backed up first, which is not
always trivial to do. Therefore, Ben’s approach, which also has “no eval”
and is “pure POSIX”, is better.

Mike Sanders

unread,
Jan 18, 2018, 7:19:44 AM1/18/18
to
Thomas 'PointedEars' Lahn <Point...@web.de> wrote:

> Jens Schweikhardt wrote:
>>
>> I'm late to this thread, so haven't seen everything that was proposed.
>> My take:
>>
>> set $(date '+%Y %m %d')
>> y=$1 m=$2 d=$3
>>
>> No eval. Pure POSIX. And since date(1) output in this case is all
>> digits, no need to worry about globbing messing up "set".
>
> The only problem with it is that it replaces *all* positional arguments;
> so if they are important, they need to be backed up first, which is not
> always trivial to do. Therefore, Ben?s approach, which also has ?no eval?
> and is ?pure POSIX?, is better.

BACKUP_ARGS=$@

Ben Bacarisse

unread,
Jan 18, 2018, 10:58:00 AM1/18/18
to
Mike Sanders <mi...@porkchop.bsd> writes:
<snip>
> BACKUP_ARGS=$@

The trouble with that is that you can't reliably recover the originals
later. It works in many cases but it's fragile.

With arrays (bash etc.) you can do

BACKUP_ARGS=("$@")

and later

set "${BACKUP_ARGS[@]}"

but if you can rely on a shell with arrays, the set idiom is rather
pointless.

--
Ben.

Mike Sanders

unread,
Jan 18, 2018, 12:02:28 PM1/18/18
to
Ben Bacarisse <ben.u...@bsb.me.uk> wrote:

>> Mike Sanders <mi...@porkchop.bsd> writes:
>>
>> BACKUP_ARGS=$@
>
> The trouble with that is that you can't
> reliably recover the originals later.
> It works in many cases but it's fragile.

You know I'm glad you brought that up...
At times I've noticed that behavior too,
almost like stale pointers or something.
As if the act of observing (funky quantum
lingo) argv, argc can have a crumbling effect.

I can certainly see the wisdom of refraining
from modification. But the need of testing
for any of presence/number/length/equivalence
is darn near imposible to avoid at times, or
at least that's been my experiance (7-8 years
under Unix).

Mike Sanders

unread,
Jan 18, 2018, 12:22:51 PM1/18/18
to
Mike Sanders <mi...@porkchop.bsd> wrote:

> I can certainly see the wisdom of refraining
> from modification. But the need of testing
> for any of presence/number/length/equivalence
> is darn near imposible to avoid at times, or
> at least that's been my experiance (7-8 years
> under Unix).

btw... (specifically presence) is this a valid test:

[ $3 ] && whatever...

Thomas 'PointedEars' Lahn

unread,
Jan 18, 2018, 2:11:49 PM1/18/18
to
Ben Bacarisse wrote:

> Mike Sanders <mi...@porkchop.bsd> writes:
> <snip>
>> BACKUP_ARGS=$@
>
> The trouble with that is that you can't reliably recover the originals
> later. It works in many cases but it's fragile.

Apparently I have found a standards-compliant way to back up positional
parameters – but boy, it’s *ugly*!

$ sh -c '
# Back up
argc=1
while [ $# -gt 0 ]
do
# Make sure there are no unescaped <"> and “$” in eval parameter
param=$(printf "%s" "$1" | sed "s/[\"$]/\\&/g")

# Work around POSIX sh’s flaw that ${param$argc}=$param does not work
eval param${argc}=\"$param\"

# POSIX sh does not have “let”
argc=$(($argc + 1))

# Not sure if iterating from 1 to $# would also work
shift
done

# set whatever

# Restore
i=1
while [ $i -lt $argc ]
do
param_value=$(eval "printf \"%s\" \"\$param$i\"")
printf "%s\n" "${param_value}"
i=$(($i + 1))
done
' sh "foo bar" "baz bla" "blubb"
foo bar
baz bla
blubb

(It becomes only slightly prettier when not wrapped as “sh -c” parameter.)

Thomas 'PointedEars' Lahn

unread,
Jan 18, 2018, 2:19:19 PM1/18/18
to
Thomas 'PointedEars' Lahn wrote:

> $ sh -c '
> # Back up
> argc=1

Replace with

argc=0

> while [ $# -gt 0 ]
> do

Move

# POSIX sh does not have “let”
argc=$(($argc + 1))

here.

> # Make sure there are no unescaped <"> and “$” in eval parameter
> param=$(printf "%s" "$1" | sed "s/[\"$]/\\&/g")
> […]
> # Work around POSIX sh’s flaw that ${param$argc}=$param does not work
> eval param${argc}=\"$param\"
>
> # Not sure if iterating from 1 to $# would also work
> shift
> done
>
> # set whatever
>
> # Restore
> i=1
> while [ $i -lt $argc ]

Replace with

while [ $i -le $argc ]

> do
> param_value=$(eval "printf \"%s\" \"\$param$i\"")
> printf "%s\n" "${param_value}"
> i=$(($i + 1))
> done
> ' sh "foo bar" "baz bla" "blubb"
> foo bar
> baz bla
> blubb

marrgol

unread,
Jan 18, 2018, 2:37:38 PM1/18/18
to
On 2018-01-18 at 02:26, Thomas 'PointedEars' Lahn wrote:
>> set $(date '+%Y %m %d')
>> y=$1 m=$2 d=$3
>>
>> No eval. Pure POSIX. And since date(1) output in this case is all
>> digits, no need to worry about globbing messing up "set".
>
> The only problem with it is that it replaces *all* positional arguments;
> so if they are important, they need to be backed up first, which is
> not always trivial to do.

Wouldn't this:

set $(date '+%Y %m %d') "$@"
y=$1 m=$2 d=$3
shift 3

be enough to preserve them?


--
mrg

Thomas 'PointedEars' Lahn

unread,
Jan 18, 2018, 3:39:14 PM1/18/18
to
</killfile>
Not necessarily, because the number of arguments to a command is limited
(ARG_MAX, NCARGS).

The address part of the From header field value of your postings constitutes
a violation of Internet standards and a disregard for netiquette. I am only
replying to your posting for this clarification.

<killfile>

marrgol

unread,
Jan 18, 2018, 4:57:15 PM1/18/18
to
On 2018-01-18 at 21:39, Thomas 'PointedEars' Lahn wrote:
> The address part of the From header field value of your postings constitutes
> a violation of Internet standards

Not according to my knowledge. RFC5537 (which obsoletes RFC1036) says:

“Contrary to [RFC5322], which implies that the mailbox or mailboxes
in the From header field should be that of the poster or posters,
a poster who does not, for whatever reason, wish to use his own
mailbox MAY use any mailbox ending in the top-level domain ".invalid"
[RFC2606].”


--
mrg

Helmut Waitzmann

unread,
Jan 18, 2018, 6:32:26 PM1/18/18
to
Ben Bacarisse <ben.u...@bsb.me.uk>:
> Mike Sanders <mi...@porkchop.bsd> writes:
> <snip>
>> BACKUP_ARGS=$@
>
> The trouble with that is that you can't reliably recover the originals
> later. It works in many cases but it's fragile.

With POSIX compliant shells, you can use the function
"my_quote_words_for_shells" (as defined below) to store the
positional parameters and restore them later using "eval", "set"
and "shift":

For example,

set '' 'These are some funny positional parameters:' \
'backslashes (\),' 'dollar signs ($),' \
'single ('\'') and double (") quotes, backticks (`)' \
'braces ({, }}, brackets ([, ]), and parantheses,' \
'even semicolons (;), ampersands (&), and' \
'parameters looking like they were commands, like' \
'date; pwd; wc </etc/passwd', \
'parameters looking like command substitution:' \
'`date; pwd`, even trailing newlines are preserved:


' && shift
printf '%s\n' "$@"

BACKUP_ARGS="$(my_quote_words_for_shells "$@")"

# Reset the positional parameters:

set some positional parameters
printf '%s\n' "$@"

# Restore the original ones later using
# "eval", "set" and "shift":

eval "set '' $BACKUP_ARGS" && shift
printf '%s\n' "$@"

my_quote_words_for_shells()
(
# Outputs a (part of) a command line resembling a 'simple command'
# to be used by a POSIX-compliant shell.
#
# Usage:
#
# my_quote_words_for_shells words to be quoted...
#
# exit code: 0, if the command line has been successfully constructed,
# !=0, if the function failed to construct the command line.
#
# Examples:
#
# Put a word list resembling a command invocation into a command line:
#
# if command_line="$(my_quote_words_for_shells \
# program with parameters)"
# then
# # "eval" it:
# eval "$command_line"
# # or invoke a new shell:
# sh -c "$command_line" sh
# # or use it remotely:
# ssh us...@remote.host.example "$command_line"
# else
# # failed to compute the command line.
# fi
#
#
# Store the shell positional parameters in a variable and restore
# them later:
#
# if args="$(my_quote_words_for_shells "$@")"
# then
# # the positional parameters may be changed for any purpose
# # ...
#
# # restore the positional parameters:
#
# eval "set '' $args" && shift
# else
# # failed to save the positional parameters.
# fi


# "wordsep" contains a separator used for the list of the quoted
# words. The first need not to be preceded by a separater:

wordsep=
for word
do
# "$wordsep" separates each word (except the first one)
# from its precedessor:
printf '%s' "$wordsep"
if test -z "$word"
then
# The word is empty. Then the result is "''":
printf '%s' "''"
else
# The word is not empty.
while
{
prefix="${word%%\'*}"
word="${word#"$prefix"}"
# "$prefix" is the longest beginning part
# of "$word", that does not contain any
# apostrophes; it is removed from "$word".
# Conclusion: "$word" is either empty or
# begins with an apostrophe.
if test -n "$prefix"
then
# "$prefix" consists of one or more
# characters. Put them in between
# of two apostrophes:
printf \''%s'\' "${prefix}"
fi
test -n "$word" &&
{
# "$word" is not empty.
# Conclusion: "$word" begins with
# one or more apostrophes.
apostr="${word%%[!\']*}"
# "$apostr" ist the longest
# beginning part of "$word", that
# contains apostrophes only.
# Put it in between of two double
# quotes:
printf '"%s"' "${apostr}"
# Remove the beginning apostrophes
# from "$word":
word="${word#"$apostr"}"
# If nothing is left, we are done:
${word:+:} false
}
}
do
:
done
fi
# All following words (except the first one) have to be
# separated from their precedessor with a blank:
wordsep=' '
done
printf '\n'
)

Helmut Waitzmann

unread,
Jan 18, 2018, 6:37:52 PM1/18/18
to
Thomas 'PointedEars' Lahn <Point...@web.de>:
will fail to preserve for example parameters, that look like
command substitution or contain newline characters, like the two
following parameters:

'`date`' 'three newlines


'

Kaz Kylheku

unread,
Jan 18, 2018, 6:50:57 PM1/18/18
to
On 2018-01-18, Helmut Waitzmann <nn.th...@xoxy.net> wrote:
> Ben Bacarisse <ben.u...@bsb.me.uk>:
>> Mike Sanders <mi...@porkchop.bsd> writes:
>> <snip>
>>> BACKUP_ARGS=$@
>>
>> The trouble with that is that you can't reliably recover the originals
>> later. It works in many cases but it's fragile.
>
> With POSIX compliant shells, you can use the function
> "my_quote_words_for_shells" (as defined below) to store the
> positional parameters and restore them later using "eval", "set"
> and "shift":

Oh goodness, reams of code.

How about simply:

backup_args()
{
local args= # local var extension
local quoted

for arg in "$@" ; do
quoted="$(printf "%s" "$arg" | sed -e s/"'"/"'\\\\''"/g)"
args="$args'$quoted' "
done

printf "%s" "$args"
}

Slight test (embedded newline, some single quotes):

$ foo=$(backup_args "a
b" c d "e'''f")
$ echo "$foo"
'a
b' 'c' 'd' 'e'\'''\'''\''f'
$ eval set -- "$foo"
$ echo "$@"
a
b c d e'''f

Chris Elvidge

unread,
Jan 18, 2018, 7:09:00 PM1/18/18
to
On 18/01/2018 11:37 pm, Helmut Waitzmann wrote:
> # POSIX sh does not have “let”
> argc=$(($argc + 1))

argc is the number of parameters on the command line. It should not be
changed in the script body (IMHO)


--

Chris Elvidge, England

Thomas 'PointedEars' Lahn

unread,
Jan 18, 2018, 7:32:08 PM1/18/18
to
Chris Elvidge wrote:

> On 18/01/2018 11:37 pm, Helmut Waitzmann wrote:
>> # POSIX sh does not have “let”
>> argc=$(($argc + 1))
>
> argc is the number of parameters on the command line.

It is, after the loop, the number of positional parameters on the command
line. Before the first assignment it is unset (unless defined in the
environment of the parent process).

> It should not be changed in the script body (IMHO)

(ba|da|k|t?c|z)?sh is case-sensitive.

Ben Bacarisse

unread,
Jan 18, 2018, 7:34:45 PM1/18/18
to
That one is worth remembering! The "set" idiom is widely used, but I
don't think I've seen this variation before. It might get expensive for
very long lists (and it could even fail) but it's likely to be practical
in many cases.

--
Ben.

Thomas 'PointedEars' Lahn

unread,
Jan 18, 2018, 7:39:40 PM1/18/18
to
Helmut Waitzmann wrote:

> will fail to preserve for example parameters, that look like
> command substitution or contain newline characters, like the two
> following parameters:
>
> '`date`' 'three newlines
>
>
> '

Yes, it is a quickhack. Some problems with it will likely go away once the
code is no longer used as parameter for “sh -c”, which requires what could
be non-expanding single-quotes to be expanding double-quotes unless one
commits to writing the safer '\'' every time instead.

Chris Elvidge

unread,
Jan 19, 2018, 6:54:40 AM1/19/18
to
On 19/01/2018 12:32 am, Thomas 'PointedEars' Lahn wrote:
> Chris Elvidge wrote:
>
>> On 18/01/2018 11:37 pm, Helmut Waitzmann wrote:
>>> # POSIX sh does not have “let”
>>> argc=$(($argc + 1))
>>
>> argc is the number of parameters on the command line.
>
> It is, after the loop, the number of positional parameters on the command
> line. Before the first assignment it is unset (unless defined in the
> environment of the parent process).
>
>> It should not be changed in the script body (IMHO)
>
> (ba|da|k|t?c|z)?sh is case-sensitive.
>

My cockup. Of course argc/argv are C not Bash. Sorry.


--

Chris Elvidge, England

Helmut Waitzmann

unread,
Jan 19, 2018, 7:24:27 AM1/19/18
to
Kaz Kylheku <217-67...@kylheku.com>:
> On 2018-01-18, Helmut Waitzmann <nn.th...@xoxy.net> wrote:
>> Ben Bacarisse <ben.u...@bsb.me.uk>:
>>> Mike Sanders <mi...@porkchop.bsd> writes:
>>> <snip>
>>>> BACKUP_ARGS=$@
>>>
>>> The trouble with that is that you can't reliably recover the originals
>>> later. It works in many cases but it's fragile.
>>
>> With POSIX compliant shells, you can use the function
>> "my_quote_words_for_shells" (as defined below) to store the
>> positional parameters and restore them later using "eval", "set"
>> and "shift":
>
> Oh goodness, reams of code.
>
> How about simply:
>
> backup_args()
> {
> local args= # local var extension
> local quoted
>
> for arg in "$@" ; do
> quoted="$(printf "%s" "$arg" | sed -e s/"'"/"'\\\\''"/g)"
> args="$args'$quoted' "
> done
>
> printf "%s" "$args"
> }

Yes, that's correct, too.

Some minor differences:

* "my_quote_words_for_shells" needs a shell, which supports
negating character sets ("[!...]"). Some ancient shells
did/do(?) not support them.

* "backup_args" using "sed" does not have this requirement. It may
fork a few processes ("sed", "printf", command substitution) for
each of the given parameters.

But nowadays probably neither the one nor the other will be a
drawback.

Helmut Waitzmann

unread,
Jan 19, 2018, 8:01:50 AM1/19/18
to
Helmut Waitzmann <nn.th...@xoxy.net>:
> Kaz Kylheku <217-67...@kylheku.com>:
>> On 2018-01-18, Helmut Waitzmann <nn.th...@xoxy.net> wrote:
>>> Ben Bacarisse <ben.u...@bsb.me.uk>:
>>>> Mike Sanders <mi...@porkchop.bsd> writes:
>>>> <snip>
>>>>> BACKUP_ARGS=$@
>>>>
>>>> The trouble with that is that you can't reliably recover the originals
>>>> later. It works in many cases but it's fragile.
>>>
>>> With POSIX compliant shells, you can use the function
>>> "my_quote_words_for_shells" (as defined below) to store the
>>> positional parameters and restore them later using "eval", "set"
>>> and "shift":
>>
>> Oh goodness, reams of code.
>>
>> How about simply:
>>
>> backup_args()
>> {
>> local args= # local var extension
>> local quoted
>>
>> for arg in "$@" ; do
>> quoted="$(printf "%s" "$arg" | sed -e s/"'"/"'\\\\''"/g)"
>> args="$args'$quoted' "
>> done
>>
>> printf "%s" "$args"
>> }
>
> Yes, that's correct, too.

I've to renounce, I'm sorry. Trailing newlines in arguments may
be removed. This is, because the command substitution used to
assign to the variable "quoted" may remove trailing newlines in
the "sed" output.

Martin Vaeth

unread,
Jan 19, 2018, 9:59:47 AM1/19/18
to
Helmut Waitzmann <nn.th...@xoxy.net> wrote:
>
> With POSIX compliant shells, you can use the function
> "my_quote_words_for_shells"

There are push https://github.com/vaeth/push/
and quoter https://github.com/vaeth/quoter/
the former being simpler in this case:

eval "`push.sh`"
Push -c SAVEDARGS ${1+"$@"}
...
eval "set -- $SAVEDARGS"

The solution with quoter does not require sourcing something:

SAVEDARGS=`quoter -- ${1+"$@"}`
...
eval "set -- $SAVEDARGS"

However, since quoter is external, calling it might exceed the maximal
admissible command line length.

Ivan Shmakov

unread,
Jan 19, 2018, 10:25:33 AM1/19/18
to
Yes. As was already pointed out in this same group last
October (e. g., [1].)

[1] news:87zi87gm...@violet.siamics.net

--
FSF associate member #7257 np. The Goat's Earth -- Jami Sieber

Ian Zimmerman

unread,
Jan 19, 2018, 11:36:43 AM1/19/18
to
On 2018-01-18 20:11, Thomas 'PointedEars' Lahn wrote:

> Apparently I have found a standards-compliant way to back up
> positional parameters – but boy, it’s *ugly*!

All this trouble just to avoid writing a shell function?

--
Please don't Cc: me privately on mailing lists and Usenet,
if you also post the followup to the list or newsgroup.
To reply privately _only_ on Usenet, fetch the TXT record for the domain.

Kaz Kylheku

unread,
Jan 19, 2018, 1:25:31 PM1/19/18
to
Thanks; here is a very simple fix:

backup_args()
{
local args= # local var extension
local quoted

for arg in "$@" ; do
quoted="$(printf "%s@" "$arg" | sed -e s/"'"/"'\\\\''"/g)"
args="$args'${quoted%@}' "
done

printf "%s" "$args"
}

marrgol

unread,
Jan 19, 2018, 1:51:14 PM1/19/18
to
On 2018-01-19 at 16:25, Ivan Shmakov wrote:
> >> The address part of the From header field value of your postings
> >> constitutes a violation of Internet standards
>
> > Not according to my knowledge. RFC5537 (which obsoletes RFC1036)
> > says:
>
> > Contrary to [RFC5322], which implies that the mailbox or mailboxes in
> > the From header field should be that of the poster or posters, a
> > poster who does not, for whatever reason, wish to use his own mailbox
> > MAY use any mailbox ending in the top-level domain ".invalid"
> > [RFC2606].
>
> Yes. As was already pointed out in this same group last
> October
 
Спасибо, Иван. :-) I saw your post last night, but after I posted
the above. Apparently Mr. Lahn refuses to acknowledge that RFC5537
is part of the Internet standards he so frequently and eagerly cites…
 
 
--
mrg

Thomas 'PointedEars' Lahn

unread,
Jan 19, 2018, 3:44:19 PM1/19/18
to
Ian Zimmerman wrote:

> On 2018-01-18 20:11, Thomas 'PointedEars' Lahn wrote:
>> Apparently I have found a standards-compliant way to back up
>> positional parameters – but boy, it’s *ugly*!
>
> All this trouble just to avoid writing a shell function?

What are you getting at?

Ian Zimmerman

unread,
Jan 20, 2018, 11:39:45 AM1/20/18
to
On 2018-01-19 21:44, Thomas 'PointedEars' Lahn wrote:

> > All this trouble just to avoid writing a shell function?
>
> What are you getting at?

If you need to back up and restore the positional parameters, why not
just put the block of code where they need to change into a function?
Every POSIX shell saves & restores them on entry to resp. exit from a
function, automatically.

Thomas 'PointedEars' Lahn

unread,
Jan 20, 2018, 12:26:52 PM1/20/18
to
Ian Zimmerman wrote:

> On 2018-01-19 21:44, Thomas 'PointedEars' Lahn wrote:
>> > All this trouble just to avoid writing a shell function?
>> What are you getting at?
>
> If you need to back up and restore the positional parameters, why not
> just put the block of code where they need to change into a function?
> Every POSIX shell saves & restores them on entry to resp. exit from a
> function, automatically.

I know that. However, I was not aware that “set” inside a function would
set the positional parameters *of the function* rather that the program.
But this behavior is supported by the wording in POSIX1-2008, “Shells and
Utilities“, §§ “2.1 Shell Introduction”, “2.5.1 Positional Parameters”,
and “14 Special Built-in Utilities”, “set”:

<http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_01>
<http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_05_01>
<http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set>

Martin Vaeth

unread,
Jan 20, 2018, 2:53:14 PM1/20/18
to
Ian Zimmerman <i...@no-use.mooo.com> wrote:
> On 2018-01-18 20:11, Thomas 'PointedEars' Lahn wrote:
>
>> Apparently I have found a standards-compliant way to back up
>> positional parameters – but boy, it’s *ugly*!
>
> All this trouble just to avoid writing a shell function?

I think we are discussing a more generic approach here
than just the particular problem.
A function may or may not be the correct solution in
some situations.
If you really just need to save the values temporarily
to use the parameter array for something else it is.
If during that "something else" you also need to access
the original (full) parameter array, things can become
more complicated.

Mike Sanders

unread,
Jan 20, 2018, 4:07:37 PM1/20/18
to
Kaz Kylheku <217-67...@kylheku.com> wrote:

> backup_args()
> {
> local args= # local var extension
> local quoted
>
> for arg in "$@" ; do
> quoted="$(printf "%s@" "$arg" | sed -e s/"'"/"'\\\\''"/g)"
> args="$args'${quoted%@}' "
> done
>
> printf "%s" "$args"
> }

Spot on. That's a keeper.

Janis Papanagnou

unread,
Jan 25, 2018, 6:01:06 PM1/25/18
to
On 17.01.2018 13:06, Mike Sanders wrote:
> Janis Papanagnou <janis_pa...@hotmail.com> wrote:
>
>> Spreaded FUD ("eval")...
>
> Not sure about this point... These are your thoughts. How
> do you /know/ that was the OP's /intent/? There are valid
> concerns about eval. Its probably best thought of as relative
> if someone asked me.

Both have been present, the poster's intent had been formulated,
and I gave an (very terse) explanation where the issue with eval
is; as said, there aren't in this case. - It makes sense to warn
folks about unsecure contexts of specific sorts of commands (like
eval), but that doesn't make it a good style to just spread FUD
instead of providing correct information.

Janis

Janis Papanagnou

unread,
Jan 25, 2018, 6:32:09 PM1/25/18
to
On 17.01.2018 17:57, Kenny McCormack wrote:
> In article <p3ne7f$qom$1...@news.albasani.net>,
> Mike Sanders <mi...@porkchop.bsd> wrote:
> ...
>>> printf "%(%Y %m %d)T" | read y m d
>>
>> Ha! Good bit of code golf.
>
> A couple of comments about this:
>
> 1) I never knew about this!

No surprise since you don't use Ksh.

> But note that it isn't standard printf(1). It

No, it is (was?) Ksh-specific (and a built-in; no external process).

> seems to exist in bash (perhaps also in ksh, since that's what Janis uses).

I had tested whether it is available in Bash, but - despite producing no
error - it didn't work as expected, and so I abstained from diving into
it. That's why I posted it in the context of saying "[in Ksh]". But I've
just looked into it and it seems it needs only another argument to work

printf "%(%Y %m %d)T\n" -1 |
{ read y m d; echo $d.$m.$y; }

As you see it doesn't solve Bash's subshell issue, and using Bash's printf's
'-v' option seems also not possible to get three different variables set.
So the other known methods are necessary [in Bash, or other shells] to get
the variables set. (Some methods have already been posted I see.)

(BTW, I also haven't tested any Ksh-clone, since (for me) Ksh is only the
"original" one. The Ksh-clones I checked in the past showed significant
differences in behaviour.)

> It is not in /usr/bin/printf.
> (Tested on a reasonably current Debian Linux system)
>
> 2) At least in bash (can't say about ksh), the above command won't work as
> expected, because the "read" gets executed in a subshell. The variable
> assignments won't be visisble in the calling shell script.

Yes, that's another feature of Ksh. (That's also one of the differences
between original Ksh and Ksh-clones that I mentioned above.)

Janis

> [...]


Janis Papanagnou

unread,
Jan 25, 2018, 6:42:32 PM1/25/18
to
On 17.01.2018 14:09, Mike Sanders wrote:
> Janis Papanagnou <janis_pa...@hotmail.com> wrote:
>
>> Even using standard awk....
>
> # experimenting...
>
> eval $( date '+m=%m y=%Y d=1' )
>
> days=$( cal $m $y | awk 'NF {days = $NF}; END {print days}' )

(Not what I was referring to when mentioning awk. Just saying.)

>
> while [ $d -le $days ]
> do
> echo fetch peanuts/$y/$m/$d
> d=$(($d+1))
> done

I recall in another thread your statement about readability and
"cognitive load". That code may be easier to grasp using modern
shell's (still non-POSIX, I suppose) arithmetic commands

while (( d <= days ))
do
...
(( d++ ))
done

or an arithmetic for loop (with assumed initial value)

for (( d=0; d<=days; d++ ))
do
...
done


Janis

Janis Papanagnou

unread,
Jan 26, 2018, 6:53:58 AM1/26/18
to
On 18.01.2018 18:22, Mike Sanders wrote:
>
> btw... (specifically presence) is this a valid test:
>
> [ $3 ] && whatever...

There are a lot of problems with that simple piece of code.
You may just want to test it with an argument of "x y", or
with '*'. So, no, that isn't a valid test, it's unreliable.
You should at least double quote the parameter. Then I'd
suggest to explicitly specify what sort of test you intend
here; there's options available to indicate that (-n, -z),
and in modern shells you also have the more robust [[...]]
syntactical test construct (which IMO has, semantically,
a much better "cognitive load" property, to use the phrase
you invented elsewhere) since it is defined more sensibly
compared to the old test command with less gotcha's and
less caveats.

Janis

Janis Papanagnou

unread,
Jan 26, 2018, 7:08:32 AM1/26/18
to
On 18.01.2018 20:37, marrgol wrote:
> On 2018-01-18 at 02:26, Thomas 'PointedEars' Lahn wrote:
>>> set $(date '+%Y %m %d')
>>> y=$1 m=$2 d=$3
>>>
>>> No eval. Pure POSIX. And since date(1) output in this case is all
>>> digits, no need to worry about globbing messing up "set".
>>
>> The only problem with it is that it replaces *all* positional arguments;
>> so if they are important, they need to be backed up first, which is
>> not always trivial to do.
>
> Wouldn't this:
>
> set $(date '+%Y %m %d') "$@"
> y=$1 m=$2 d=$3
> shift 3
>
> be enough to preserve them?

Yes, I would think so. Nice pattern! (For modern shells you can also use
${@:1:3} and ${@:4} to access the parameter subsets, just BTW.) While for
parameters passed through the exec-environment, where you have the known
limits, it should be safe use while in the shell context. I just checked
some of the modern shells' behaviour and there seems no practical limit
(tested with more than a million arguments, in Ksh, Bash, Zsh).

Janis

Janis Papanagnou

unread,
Jan 26, 2018, 7:50:37 AM1/26/18
to
On 17.01.2018 02:50, Ivan Shmakov wrote:
>>>>>> Janis Papanagnou <janis_pa...@hotmail.com> writes:
>
> > Eval can become a problem in cases where you process (for example)
> > uninterpreted and untested user input. But that is irrelevant here;
> > above construct is absolutely safe.
>
> I see no reason to challenge the safety of date(1) to produce
> eval-friendly key=value output in this specific case. (I would
> be wary of accepting it were it to feature any locale-dependent
> format sequence, though, as I'm not entirely sure that no locale
> can possibly use Shell special characters in this context.)

You may want to have a look into this compilation where you can easily
identify arguments of date that create locale dependent outputs:

http://volatile.gridbug.de/tifosp.html

In a nutshell; it's only the name related options (like March, Thursday),
the AM/PM qualifiers, and the digit group-separators in two of the
predefined composite time/date formats (%x, %X).

Even if we assume that in some locale names of weekdays or months may
contain some shell meta-characters - hardly to believe that's possible,
but examples welcome -, the case we're discussing here - simple groups
of digits! - generally don't have any issues.

There's really no reason to be reluctant using eval here. More complex
alternatives usually add even more uncertaincies (or even bugs, as we've
seen). If I have a choice I prefer simplicity ("to manage complexity").

Janis

Janis Papanagnou

unread,
Jan 26, 2018, 8:07:52 AM1/26/18
to
On 26.01.2018 13:50, Janis Papanagnou wrote:
[ locale specific date(1) output ]
>
> http://volatile.gridbug.de/tifosp.html
>
> In a nutshell; it's only the name related options (like March, Thursday),
> the AM/PM qualifiers, and the digit group-separators in two of the
> predefined composite time/date formats (%x, %X).

Oops, I forgot to mention the (here rarely seen) %E and %O format classes,
which are specifically used to represent locale specific information, e.g.
for "alternative numbers" (as used in other cultures, AFAIU, that are not
used to "arabic" numbers)

%E - use of locale specific alternative representation
(defined for %Ec, %EC, %Ex, %EX, %Ey, %EY)
%O - use of locale specific alternative numeric symbols
(defined for %Od, %Oe, %OH, %OI, %Om, %OM, %OS, %Ou, %OU, %OV, %Ow,
%OW, %Oy)

I have no idea what a date command would generally output in such cases.
In Japan (for example), maybe the japanese numeric character symbols?

Mot relevant for the given eval case, but obviously relevant to folks who
specifically ask date(1) for the locale specific cases.

Janis

> [...]


Mike Sanders

unread,
Jan 26, 2018, 10:37:52 AM1/26/18
to
Janis Papanagnou <janis_pa...@hotmail.com> wrote:

>> [ $3 ] && whatever...
>
> it's unreliable...

What I'm speaking of is only a wish of course.
It would be nice using standard /bin/sh to test
for the presence of $3 (or any other param) in
such a fashion without a switch (not '-z', not
'-n', not '$#' just existence). In other words:

'if ($3) {}'

We can in c, awk, js, etc. Would be nice in some cases
for /bin/sh I think.

> cognitive load...

No no, not me Janis, only to help the OP. Me? If I can't discern
a snippet, I'll study &/or ask questions. In *that particular
case* we should make it easier not harder... While everyone
is telling me 'do this instead to improve efficiency' I say no,
*improve readability 1st* for newbies *then optimize*. When
someone asks for help, don't hit them over the head with shell
globing. Instead, 1st present an easy example. I understand
in the other thread that shell globing is more efficient than
a subshell + tr. I want to make it easier for a *human to read*
& hopefully understand in the initial stages of the conversation.

Janis Papanagnou

unread,
Jan 26, 2018, 10:59:35 AM1/26/18
to
On 26.01.2018 16:37, Mike Sanders wrote:
> Janis Papanagnou <janis_pa...@hotmail.com> wrote:
>
>>> [ $3 ] && whatever...
>>
>> it's unreliable...
>
> What I'm speaking of is only a wish of course.
> It would be nice using standard /bin/sh to test
> for the presence of $3 (or any other param) in
> such a fashion without a switch (not '-z', not
> '-n', not '$#' just existence). In other words:
>
> 'if ($3) {}'
>
> We can in c, awk, js, etc. Would be nice in some cases
> for /bin/sh I think.

It's defined in the POSIX standard (if that's what you wanted
to know): "True if the string string is not the null string;
otherwise, false." (But beware the necessary quoting, as said.)

>
>> cognitive load...
>
> No no, not me Janis, only to help the OP. Me? If I can't discern
> a snippet, I'll study &/or ask questions. In *that particular
> case* we should make it easier not harder... While everyone
> is telling me 'do this instead to improve efficiency' I say no,

(I wasn't speaking of efficiency here, but of semantical complexity,
caveats, etc.)

> *improve readability 1st* for newbies *then optimize*. When
> someone asks for help, don't hit them over the head with shell
> globing. Instead, 1st present an easy example. I understand
> in the other thread that shell globing is more efficient than
> a subshell + tr. I want to make it easier for a *human to read*
> & hopefully understand in the initial stages of the conversation.

What I patricularly tried to express here was that, from a syntax
point of view, [...] and [[...]] are of equal "complexity", but
from a semantical point of view [...] is worse than [[...]]. (This
is true not only for newbies.)

What your primary factors are (POSIX, simplicity, efficiency, or
readability) is completely your business; it just seems to not be
very coherent if I recall your posts and preferred code. Not that
I mind, neither I intend any offense, but argumenting on that base
appears to become difficult under that stance.

Janis

Mike Sanders

unread,
Jan 26, 2018, 11:05:52 AM1/26/18
to
Janis Papanagnou <janis_pa...@hotmail.com> wrote:

> What your primary factors are (POSIX, simplicity, efficiency, or
> readability) is completely your business; it just seems to not be
> very coherent if I recall your posts and preferred code. Not that
> I mind, neither I intend any offense, but argumenting on that base
> appears to become difficult under that stance.

<https://busybox.hypermart.net/winning-at-wordsmanship.html>

Ian Zimmerman

unread,
Jan 26, 2018, 1:03:02 PM1/26/18
to
On 2018-01-26 00:42, Janis Papanagnou wrote:

> (still non-POSIX, I suppose) arithmetic commands
>
> while (( d <= days ))
> do
> ...
> (( d++ ))
> done

In a strictly POSIX shell, you can define functions for this purpose:

nonzero()
{
case $1 in
(0)
return 1;;
(*)
return 0;;
esac
}

while nonzero $(( d <= days )) ; do
...

or even better:

upto()
{
local loopfrom loopto looparg
loopfrom=$1 loopto=$2 ; shift 2
looparg=$loopfrom
while : ; do
case $(( loopto - looparg )) in
(-*)
break
;;
esac
"$@"
looparg=$(( looparg + 1 ))
done
}

(note that dynamic scoping is in effect so "$@" can refer to $looparg)

Helmut Waitzmann

unread,
Jan 26, 2018, 8:48:10 PM1/26/18
to
Mike Sanders <mi...@porkchop.bsd>:
> Janis Papanagnou <janis_pa...@hotmail.com> wrote:
>
>>> [ $3 ] && whatever...
>>
>> it's unreliable...
>
> What I'm speaking of is only a wish of course.
> It would be nice using standard /bin/sh to test
> for the presence of $3 (or any other param) in
> such a fashion without a switch (not '-z', not
> '-n', not '$#' just existence). In other words:
>
> 'if ($3) {}'
>
> We can in c, awk, js, etc. Would be nice in some cases
> for /bin/sh I think.

The following commands return with a zero exit status, if the
third positional parameter is defined, i.e. exists. They return
with a non-zero exit status, if the third positional parameter is
not defined, i.e. does not exist.

${3+:} false

test "${3+exists}"

Helmut Waitzmann

unread,
Jan 26, 2018, 8:54:25 PM1/26/18
to
Mike Sanders <mi...@porkchop.bsd>:
> Janis Papanagnou <janis_pa...@hotmail.com> wrote:
>
>>> [ $3 ] && whatever...
>>
>> it's unreliable...
>
> What I'm speaking of is only a wish of course.
> It would be nice using standard /bin/sh to test
> for the presence of $3 (or any other param) in
> such a fashion without a switch (not '-z', not
> '-n', not '$#' just existence). In other words:
>
> 'if ($3) {}'
>
> We can in c, awk, js, etc. Would be nice in some cases
> for /bin/sh I think.

Allodoxaphobia

unread,
Jan 26, 2018, 9:52:38 PM1/26/18
to
On Fri, 26 Jan 2018 16:05:49 +0000 (UTC), Mike Sanders wrote:
>
><https://busybox.hypermart.net/winning-at-wordsmanship.html>

Missing from column 2 is "orthogonal".
I *just love* orthogonal!

Jonesy

Mike Sanders

unread,
Jan 27, 2018, 11:49:43 AM1/27/18
to
Helmut Waitzmann <nn.th...@xoxy.net> wrote:

> The following commands return with a zero exit status, if the
> third positional parameter is defined, i.e. exists. They return
> with a non-zero exit status, if the third positional parameter is
> not defined, i.e. does not exist.
>
> ${3+:} false
>
> test "${3+exists}"

Ahh... (many thanks)

$ echo $SHELL
$ /bin/sh

$ cat ./example
#!/bin/sh
${3+:} false
echo $?
# eof

$ ./example
$ 1

$ ./example x
$ 1

$ ./example x y
$ 1

$ ./example x y z
$ 0

$ ./example x y z n
$ 1

A question for you Helmut... is the following portable?

[ $3 ] && echo defined || echo not

Background: Recently I was talking with someone who is
very trustworthy & was told the above was not portable.
The argument against it was that both '[' & 'test' require,
an expression of course, as well as a *mandatory* switch
('-z', etc).

The man pages I've read are silent with respect to a
mandatory switch. And it works perfectly for me as shown...
My targeted shells all consider '[' & its closing bracket ']'
a builtin. I want to use it, but because of the advice
against it, have not yet done so...

Mike Sanders

unread,
Jan 27, 2018, 11:50:49 AM1/27/18
to
Allodoxaphobia <knock_you...@example.net> wrote:

> Missing from column 2 is "orthogonal".
> I *just love* orthogonal!

Well now, 'look what the cat done dragged in' =)

Chuckle, one of these days I'll try to work it in.
Certainly does have that 'ring' of authority.

Hang around if so compelled. Mucho brain-food &
free beer. Err, well, I havent actually found
the beer yet, but it could happen!
It is loading more messages.
0 new messages