How do I programmatically determine operating system in Java?
I would like to determine the operating system of the host that my Java program is running programmatically (for example: I would like to be able to load different properties based on whether I am on a Windows or Unix platform). What is the safest way to do this with 100% reliability?
22 Answers 22
P.S. You may find this code useful:
All it does is print out all the properties provided by your Java implementations. It’ll give you an idea of what you can find out about your Java environment via properties. 🙂
As indicated in other answers, System.getProperty provides the raw data. However, the Apache Commons Lang component provides a wrapper for java.lang.System with handy properties like SystemUtils.IS_OS_WINDOWS , much like the aforementioned Swingx OS util.
I would recommend to cache it in a static variable:
public static final class OsUtils < private static String OS = null; public static String getOsName() < if(OS == null) < OS = System.getProperty("os.name"); >return OS; > public static boolean isWindows() < return getOsName().startsWith("Windows"); >public static boolean isUnix() // and so on >
That way, every time you ask for the Os, you do not fetch the property more than once in the lifetime of your application.
February 2016: 7+ years later:
There is a bug with Windows 10 (which did not exist at the time of the original answer).
See «Java’s “os.name” for Windows 10?»
I agree with the getOSName function, on the basis of OAOO (once and only once); however, the caching is totally redundant given the speed of hash lookups.
Totally redundant might be a bit harsh, hash lookups are more expensive than accessing a reference. It all depends on the context.
I reread this answer. If you are going to cache, cache the values of isWindows , isUnix , etc. That way you save on the string comparison time also.
some of the links in the answers above seem to be broken. I have added pointers to current source code in the code below and offer an approach for handling the check with an enum as an answer so that a switch statement can be used when evaluating the result:
OsCheck.OSType ostype=OsCheck.getOperatingSystemType(); switch (ostype)
/** * helper class to check the operating system this Java VM runs in * * please keep the notes below as a pseudo-license * * http://stackoverflow.com/questions/228477/how-do-i-programmatically-determine-operating-system-in-java * compare to http://svn.terracotta.org/svn/tc/dso/tags/2.6.4/code/base/common/src/com/tc/util/runtime/Os.java * http://www.docjar.com/html/api/org/apache/commons/lang/SystemUtils.java.html */ import java.util.Locale; public static final class OsCheck < /** * types of Operating Systems */ public enum OSType < Windows, MacOS, Linux, Other >; // cached result of OS detection protected static OSType detectedOS; /** * detect the operating system from the os.name System property and cache * the result * * @returns - the operating system detected */ public static OSType getOperatingSystemType() < if (detectedOS == null) < String OS = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH); if ((OS.indexOf("mac") >= 0) || (OS.indexOf("darwin") >= 0)) < detectedOS = OSType.MacOS; >else if (OS.indexOf("win") >= 0) < detectedOS = OSType.Windows; >else if (OS.indexOf("nux") >= 0) < detectedOS = OSType.Linux; >else < detectedOS = OSType.Other; >> return detectedOS; > >
The code above may have locale issues, since it uses toLowerCase(), which is locale sensitive. Where this matters is particularly when converting i’s to lower/upper case, since in Turkey, I becomes lower case undotted i (ı), and i becomes upper case dotted i (İ). So «WINDOWS».toLowerCase().indexOf(«win») will return -1 in Turkey. Always pass a locale when doing a lower case of a particular language, ie «WINDOWS».toLowerCase(Locale.ENGLISH).indexOf(«win») will work in Turkey.
The following JavaFX classes have static methods to determine current OS (isWindows(),isLinux(). ):
- com.sun.javafx.PlatformUtil
- com.sun.media.jfxmediaimpl.HostUtils
- com.sun.javafx.util.Utils
Please note that the access to «com/sun/javafx/*» is discouraged now (checked it with JDK 1.8.0_121).
@HummelingEngineeringBV: I guess it was a mistake from my side. I am working with eclipse Neon 4.6.3 and the «Java Build Path» shows several «Discouraged: com/sun/javafx/**» warnings. However, as I found out, this happens to be an eclipse-bug and/or -feature (see link).
I have to correct myself one more time. Beginning with Java 9/10+, several «com.sun.*» packages/APIs are about to be removed. Check out this link for more info. I actually stumbled over this because we use some of these packages. Migrating to eclipse 4.8/JDK 10, we now have to fix these and several other compiler errors due to missing references.
For accessing OS use: System.getProperty(«os.name») .
But WAIT.
Why not create a utility class, make it reusable! And probably much faster on multiple calls. Clean, clear, faster!
Create a Util class for such utility functions. Then create public enums for each operating system type.
public class Util < public enum OS < WINDOWS, LINUX, MAC, SOLARIS >;// Operating systems. private static OS os = null; public static OS getOS() < if (os == null) < String operSys = System.getProperty("os.name").toLowerCase(); if (operSys.contains("win")) < os = OS.WINDOWS; >else if (operSys.contains("nix") || operSys.contains("nux") || operSys.contains("aix")) < os = OS.LINUX; >else if (operSys.contains("mac")) < os = OS.MAC; >else if (operSys.contains("sunos")) < os = OS.SOLARIS; >> return os; > >
Now, you can easily invoke class from any class as follows,(P.S. Since we declared os variable as static, it will consume time only once to identify the system type, then it can be used until your application halts. )
I want to use this piece of code in an open-source project (github.com/openhab/openhab-addons), is this okay with you?
Go ahead and put rationale for why you said so. I am happy to change the code if you have any reasonable evidence. Be reasonable and clarify your comment please, so that I can improve my 7-8 years old answer.
A small example of what you’re trying to achieve would probably be a class similar to what’s underneath:
import java.util.Locale; public class OperatingSystem < private static String OS = System.getProperty("os.name", "unknown").toLowerCase(Locale.ROOT); public static boolean isWindows() < return OS.contains("win"); >public static boolean isMac() < return OS.contains("mac"); >public static boolean isUnix() < return OS.contains("nux"); >>
This particular implementation is quite reliable and should be universally applicable. Just copy and paste it into your class of choice.
Why make it so complicated? System.getProperty(«os.name») is sufficient. Don’t bother with the unnecessary fluff.
System.getProperty("os.name"); System.getProperty("os.version"); System.getProperty("os.arch");
If you’re interested in how an open source project does stuff like this, you can check out the Terracotta class (Os.java) that handles this junk here:
And you can see a similar class to handle JVM versions (Vm.java and VmVersion.java) here:
also suffers from the same issue identified by James Roper in Wolfgang Fahl’s answer — use of toLowerCase without specifying a locale
I think following can give broader coverage in fewer lines
import org.apache.commons.exec.OS; if (OS.isFamilyWindows()) < //load some property >else if (OS.isFamilyUnix()) < //load some other property >
If you’re working in a security sensitive environment, then please read this through.
Please refrain from ever trusting a property obtained via the System#getProperty(String) subroutine! Actually, almost every property including os.arch , os.name , and os.version isn’t readonly as you’d might expect — instead, they’re actually quite the opposite.
First of all, any code with sufficient permission of invoking the System#setProperty(String, String) subroutine can modify the returned literal at will. However, that’s not necessarily the primary issue here, as it can be resolved through the use of a so called SecurityManager , as described in greater detail over here.
The actual issue is that any user is able to edit these properties when running the JAR in question (through -Dos.name= , -Dos.arch= , etc.). A possible way to avoid tampering with the application parameters is by querying the RuntimeMXBean as shown here. The following code snippet should provide some insight into how this may be achieved.
RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean(); List arguments = runtimeMxBean.getInputArguments(); for (String argument : arguments) < if (argument.startsWith("-Dos.name") < // System.getProperty("os.name") altered >else if (argument.startsWith("-Dos.arch") < // System.getProperty("os.arch") altered >>
How can I detect a Unix-like OS in Java?
Ok, I know that System.getProperty(«os.name») will give me the name of the OS I’m running under, but that’s not a lot of help. What I need to know is if the OS I’m running on is a ‘Unix-like’ OS, I don’t care if it’s HP-UX, AIX, Mac OS X or whatever. From the list of possible os.name values it seems like a quick and dirty way of detecting a ‘Unix-like’ OS is checking if os.name does not contain «Windows». The false positives that will give me are OSes my code is very unlikely to encounter! Still, I’d love to know a better way if there is one.
Is there a particular reason you’re looking for «Unix-like»? If you’re looking for a particular feature, it might be better to check that feature.
«Yes, there are often ways where you could get around this sort of thing with pristine Java, but sometimes it’s just not worth the trouble» . Yes it IS worth the trouble. If you use Java.io.file.list, download.oracle.com/docs/cd/E17476_01/javase/1.4.2/docs/api/… You get a directory listing and you avoid making syscalls to ls or dir and you avoid OS detection logic. Using an OS independent API call is ALWAYS better than fiddling with OS detection logic.
Just as an extra warning, trying specific commands could be unhelpful too (depending on what machines you might end up on) — uname, ls, etc all work on my Windows machine, because I have MinGW+MSYS installed.
The reason I want to detect if I’m on a Unix-like OS is because I’m creating directories which, when on Unix, I need to «chmod» to open write permissions to everyone. I don’t want (or need) to be calling «chmod» when running on Windows. AFAIK Java doesn’t have an OS independent API for changing file permissions.
9 Answers 9
Use the org.apache.commons.lang.SystemUtils utility class from Commons Lang, it has a nice IS_OS_UNIX constant. From the javadoc:
Is true if this is a POSIX compilant system, as in any of AIX, HP-UX, Irix, Linux, MacOSX, Solaris or SUN OS.
The field will return false if OS_NAME is null.
Simple, effective, easy to read, no cryptic tricks.
@Anders: First of all, let me underline that we are talking about javadoc here. Did you check the implementation before claiming it’s wrong? Second, what is utterly wrong with the list, what would you add? Last thing, feel free to submit a javadoc patch, patches are often welcome if they can improve something.
Last time I looked there were more then a fair share of different Linux distributions, even the oldest one (Slackware) is not POSIX compliant, honestly I don’t believe a single one can claim to be. Neither is quite Solaris nor SUN OS (which really should now be the same), and MacOSX is not POSIX compliant either. And no, I did not check the implementation. I will revise the first comment, hopefully the implementation is better then the documentation.
@Anders: Thanks for the feedback and clarification, I get your point (and I can agree now, the javadoc is not good).
I’ve used your scheme in production code on Windows XP, Vista, Win7, Mac OS 10.3 — 10.6 and a variety of Linux distros without an issue:
if (System.getProperty("os.name").startsWith("Windows")) < // includes: Windows 2000, Windows 95, Windows 98, Windows NT, Windows Vista, Windows XP >else < // everything else >
Essentially, detect Unix-like by not detecting Windows.
Despite the many good ideas posted (I particularly liked File.listRoots) I think this is the «correct» way to do it. False positives are highly unlikely.
Won’t this not work if someone is using an OS like ReactOS? It is certainly not Unix-like, but it’s not Windows either.
@Arin. Agreed. Eight year old answer is showing it’s age. I’ll make it community wiki and have at it.
File.listRoots() will give you an array of the file system root directories.
If you are on a Unix-like system, then the array should contain a single entry «/» and on Windows systems you’ll get something like [«C:», «D:», . ]
Edit: @chris_l: I totally forgot about mobile phones. Some digging turns up that Android returns a «/\0\0» — a slash followed by two null bytes (assumed to be a bug). Looks like we avoid false positives for the time being through luck and coincidence. Couldn’t find good data on other phones, unfortunately.
It’s probably not a good idea to run the same code on desktops and mobile phones regardless, but it is interesting to know. Looks like it comes down to needing to check for specific features instead of simply the system type.