Shell script question

If you’re behind a router with a masqueraded DHCP address, it’s of interest to know both your internal and external IP addresses. These will do it:

-- Using http://checkip.dyndns.org/
set Ext_IP to word 25 of (do shell script "curl checkip.dyndns.org")
set Int_IP to do shell script ("ipconfig getifaddr en0")

But these involve two separate “do shell script” calls. Is there a simple way to combine these in a single shell script returning both answers?

This will do it

-- Using http://checkip.dyndns.org/
set IPinfo to (do shell script "curl checkip.dyndns.org;ipconfig getifaddr en0")
set Ext_IP to word 25 of IPinfo
set Int_IP to word 32 of IPinfo

or if you prefer one-liner style (which I do)

set {Ext_IP, Int_IP} to {word 25, word 32} of (do shell script "curl checkip.dyndns.org;ipconfig getifaddr en0")

Thanks, I do prefer the one-liner. I would have used word -1 for the inside.

Not a problem Im sitting around bored out of my mind trolling here and on the Apple AS mailing list =)

I actually had no idea the

set {} to {word, word} of blah

would work so I was pleasantly surprised when it did. I’m all about least amount of code possible.

Yup; It’s really handy for things like this:

tell (current date) to set {yr, mo, dy, hr, mn, sc, wd} to {its year, its month as number, its day, its hours, its minutes, its seconds, its weekday as number}

Since you can’t be guaranteed which word it’ll be (who knows when it’ll change), or if you want to be a little more portable, try this instead for pulling the IP out of the page:

/usr/bin/curl -s http://checkip.dyndns.org/ | /usr/bin/grep -o -e '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'

If integrated into AppleScript, remember that the shell escapes require additional escapes for AppleScript:

do shell script "/usr/bin/curl -s http://checkip.dyndns.org/ | /usr/bin/grep -o -e '[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}'"

Excellent. My problem, of course is that I can’t construct the RegEx, although this one seems not too awful to read.

-o → Only the part of the line matched by the pattern
-e → RegEx to follow, use it

[0-9] {1,3} → look for between 1 and 3 digits 0 thru 9
period → itself, a period
repeat of the 1 to 3 digits
period
etc. until 4 sets are found side by side.

EDIT:
I kinda like it this way:

set IPRegEx to quoted form of "[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}"
do shell script "/usr/bin/curl -s http://checkip.dyndns.org/ | /usr/bin/grep -o -e " & IPRegEx

So our one-liner becomes:

set {Ext_IP, Int_IP} to paragraphs of (do shell script "curl -s checkip.dyndns.org | grep -o -e '[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}';ipconfig getifaddr en0")

Shorter still and slightly faster:

tell (current date) to set {{year:yr, day:dy, hours:hr, minutes:mn, seconds:sc}, mo, wd} to {it, (its month) * 1, (its weekday) * 1}

:wink:

Interesting, Nigel, that month and weekday require its while year, day, hours, minutes & seconds do not. In the example you quoted I put its in every one rather than confuse a relative newcomer about which was which.

Didn’t think to use the record trick for it because it wouldn’t do month or weekday as numbers - didn’t think to do it in parts.

Thanks.

I think the following is more readable:

-- Pattern could also be the slightly better '([[:digit:]]{1,3}\\.){3}[[:digit:]]{1,3}'
set {ipExternal, ipInternal} to paragraphs of (do shell script "/usr/bin/curl -s http://checkip.dyndns.org/ | /usr/bin/grep -Eo '([[:digit:]]{1,3}\\.?){4}'; ipconfig getifaddr en0")

'Tis indeed, QD. Duly noted. I wondered how to do multiples.

Insert massive, intricate, precise rant about AppleScript’s ridiculous syntax. :wink:

More accurately, in the context of setting variables by record, none of the date properties requires its, because that’s understood in the situation. The properties of the record are the same as the properties of the date.

In a tell statement, there’s ambiguity. hours and minutes are also AppleScript constants. I think that month and weekday are class names. seconds is a keyword used in with timeout statements. When these are intended as properties of a date, they have to be used in a reference that associates them with that date.

year, day and time currently have no meaning outside of a possessive context, so, if they’re used without one in a tell statement, the compiler tries to associate them with the object of the tell.

Sorry. This has nothing at all to do with your original query. :rolleyes:

Out of context or not, thanks for the explanation. As is often the case, keywords belonging to more than one context.

I always forget about [:digit:].

Additionally, [:digit:] should be faster than the ranged character classes. (Not that you’re going to notice it, but it’s worth pointing out.)