[sf-lug] nifty sh + DNS wizardry there ... IFS, subshell, environment for command only ...
Michael.Paoli at cal.berkeley.edu
Mon Nov 15 00:51:22 PST 2021
> From: "Michael Paoli" <Michael.Paoli at cal.berkeley.edu>
> Subject: nifty sh + DNS wizardry there ... IFS, subshell,
> environment for command only ...
> Date: Sun, 14 Nov 2021 14:08:04 -0800
>> From: "Ronald Barnes" <ron at ronaldbarnes.ca>
>> Subject: Re: [sf-lug] Notice: ns1.svlug.org downtime, DNS secondary
>> Date: Sun, 14 Nov 2021 12:39:05 -0800
>> Michael Paoli wrote on 2021-11-14 7:57 a.m.:
>>> echo 'sf-lug.com.
>>> sf-lug.net.' | (
>>> while IFS="$IFS_" read subdomain TLD
>>> Authority_NS="$(dig +short "$TLD". NS | head -n 1)"
>>> Authority_NS_IP="$(dig +short "$Authority_NS" A
>>> "$Authority_NS" AAAA | head -n 1)"
>>> dig @"$Authority_NS_IP" +noall +authority +norecurse
>>> "$subdomain.$TLD." | fgrep -i svlug || echo OK
>>> ) | sort -u
>> That's some nifty bash + DNS wizardry there.
>> But I was really thrown by the Internal Field Separator magic - why
>> inside the "while" loop?
>> I tested it on the outside and got similar results, is it just a
>> stylistic preference?
>> And how does IFS get reset to original value (minus the ".") after
>> the script has run?
> I set IFS_ within a subshell (...), so it's not set/changed outside of that
> subshell. And then I only have IFS set different for the read
> command, so only the read command sees the altered value of IFS.
> You can set stuff in the environment
> whatever=... export whatever
> But you can also set it just for a command, don't even need env,
> FOO=foo BAR=bar some_command ...
> then it's set only for that command, and otherwise changed.
> Using IFS with non-default setting can cause quite unexpected side
> effects, so generally best, when setting it to something else,
> to quite carefully limit it's scope - in this case I limit it's
> scope to just the read command ... and IFS_'s to just the subshell.
> And by doing that all in shell, didn't need to bring in awk or sed or
> anything like that, and no non-POSIX RE extensions, or anything like
> that either.
> And no bash required, sh will do fine, thankyouverymuch.
And ... can optimize even further, really:
while IFS=".$IFS" read subdomain TLD
Authority_NS="$(dig +short "$TLD". NS | head -n 1)"
Authority_NS_IP="$(dig +short "$Authority_NS" A "$Authority_NS" \
AAAA | head -n 1)"
dig @"$Authority_NS_IP" +noall +authority +norecurse \
"$subdomain.$TLD." | fgrep -i svlug || echo OK
That will do it quite well, and with less overhead.
Since IFS is only altered in the form:
ENV_VAR=something... command ...
IFS=".$IFS" read subdomain TLD
as the list/command provided as the conditional of the while command,
IFS is never otherwise altered at all, so even with the repeated running
of the while loop, for each iteration,
in that context, each times through sees IFS as its original value,
then sets IFS in the environment with a prepended ".", but only
for the read command. So ... can dispense with the subshell
and the IFS_ - no need for any of that.
More information about the sf-lug