Code to get local IP on all platforms

Dear users and developers,

I have found an old thread regarding this theme:
https://listarc.cal.bham.ac.uk/lists/sc-users-2015/msg46783.html

Based on this thread, I constructed two codes which detect the local IP address as follows:

(
var winCMD, macCMD, linuxCMD;

winCMD = {var ipv4; ipv4 = "ipconfig | findstr /C:IPv4".unixCmdGetStdOut; ipv4.[39..ipv4.size-1]};
// works under Windows 11.

macCMD = { |device| ("ipconfig getifaddr" + device).unixCmdGetStdOut};
// works under macOS 10.14 and 12.2.1.

linuxCMD = { "hostname -I | awk '{print $1}'".unixCmdGetStdOut};
// works under Ubuntu 20.04.3.

~ip = Platform.case(
	\osx,       { var ethernet = macCMD.("en1"); (ethernet=="").if {macCMD.("en0") } { ethernet } },
	\linux,     { linuxCMD.() },
	\windows,   { winCMD.() }
)
)
(
// works under macOS 12.2.1, Ubuntu 20.04.3 and Windows 11.
// Under Windows, Python3 should be installed using "Microsoft Store" to automatically register the Python path.
~ip = {
var pythonStatements = [
"import socket",
"s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)",
"s.connect(('8.8.8.8', 80))",
"print(s.getsockname()[0])"
];
var cmd = "python3 -c \"" ++ pythonStatements.join("; ") ++ "\"";
var ipaddr = cmd.unixCmdGetStdOut.stripWhiteSpace;
ipaddr
}.()
)

On my end, the first code block works as commented in the code without problems. I hope it could generally be applicable, but I am unsure.

Regarding the second code, however, SC-IDE does not respond after evaluating that code under Windows. Therefore, I cannot quit the interpreter, and I should quit the SC-IDE and then restart it. Thus, the second code is not usable under Windows. Why does this problem happen solely under Windows?

Best regards,

Just a few comments here:

  • depending on python to get one’s IP is a rather heavy dependency. Sure, python is most likely found in most Linux distros, but it’s not guaranteed; python2 comes standard with macOS, but python3 needs to be installed separately; on Windows it’s not provided by default and even if installed one would need to make sure it’s included in %PATH% env variable; depending on most standard system commands is preferable
  • IMO the command to check for one’s IP should always return an array (excluding 127.0.0.1) - it’s not uncommon to have more than one interface (e.g. wireless and ethernet) and it’s not always clear which one you’d want to know about. Also, they should probably be listed in the order they are set in the OS
    • in this spirit I believe that there should be a separate command to get all addresses, and a separate one to get it for a specific interface
  • NetLib has an implementation for Linux and macOS (NetAddr.myIP), though I think it might not always work on macOS IIRC
    • it lists a single address, even if multiple interfaces are available

Thanks for your kind comments. I reconstructed the code. The code below now outputs an array consisting of local IPs (or an array with one local IP if there is only one) except “127.0.0.1”.

It successfully detects multiple IPv4 addresses as well as one IPv4 address under macOS 12.2.1 and Windows 11. However, under Ubuntu 20.04.3, which ran over Parallels Desktop, I strangely could not assign IPv4 to the second network card. Thus, I confirmed only the output of an array with one IP, but I hope it also could output multiple IPs.

// The following strings are to avoid listing network bridges which seem to be created by Parallels Desktop:
// | grep -Fv "inet 10."  

(
~ip = { 
	var winCMD, macCMD, linCMD, ips;

	winCMD = {var ipInfo, ipv4s; ipInfo = "ipconfig | findstr /C:IPv4".unixCmdGetStdOut.replace("   IPv4 Address. . . . . . . . . . . : ", "")};
	macCMD = { ("ifconfig | grep -Fv" + "inet 10.".quote + "| grep" + "inet ".quote + "| grep -Fv 127.0.0.1 | awk '{print $2}'").unixCmdGetStdOut };
	linCMD = { ("ifconfig | grep" + "inet ".quote + "| grep -Fv 127.0.0.1 | awk '{print $2}'").unixCmdGetStdOut };
	
	ips = Platform.case(
		\osx,       { macCMD.() },
		\linux,     { linCMD.() },
		\windows,   { winCMD.() }
	);

	ips = ips.split(Char.nl);
	ips.removeAt(ips.size-1);
	ips
}.()
)
2 Likes