[sf-lug] nifty sh + DNS wizardry there ... IFS, subshell, environment for command only ...

Michael Paoli 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.
>>> sflug.org.
>>> sflug.com.
>>> sflug.net.
>>> sf-lug.net.' | (
>>>   IFS_=".$IFS";
>>>   while IFS="$IFS_" read subdomain TLD
>>>   do
>>>     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
>>>   done
>>> ) | sort -u
>>> OK
>>
>> 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,
> e.g.
> 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:

echo 'sf-lug.com.
sflug.org.
sflug.com.
sflug.net.
sf-lug.net.' |
   while IFS=".$IFS" read subdomain TLD
   do
     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
   done |
sort -u
OK

That will do it quite well, and with less overhead.
Since IFS is only altered in the form:
ENV_VAR=something... command ...
specifically
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,
IFS=".$IFS"
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 mailing list