35

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.

mluisbrown
  • 14,448
  • 7
  • 58
  • 86
  • 4
    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. – David Thornley Jul 19 '10 at 15:39
  • The main reason why I sometimes want to know is because filenames will be different, especially if you have hard-coded filenames, e.g. as defaults. Like, on Windows I may create "c:\myapp\myapp.properties", while on Linux it will be "/myapp/myapp.properties". Or if you're interacting with the OS, like on Linux I want to execute an "ls" command while on Windows I want to do a "dir". 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. – Jay Jul 19 '10 at 16:34
  • 5
    "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, http://download.oracle.com/docs/cd/E17476_01/javase/1.4.2/docs/api/java/io/File.html#list() 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. – Freiheit Jul 19 '10 at 18:24
  • 1
    Java has no need for that functionality ;) – Brendan Long Jul 19 '10 at 21:02
  • 6
    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. – mluisbrown Jul 21 '10 at 09:00
  • 1
    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... – Jonathan Jul 19 '10 at 22:34
  • Just for the fun of it. You could test `System.getProperty("line.separator")`... – Martin Jul 19 '10 at 21:00
  • possible duplicate of [How do I programmatically determine operating system in Java?](http://stackoverflow.com/questions/228477/how-do-i-programmatically-determine-operating-system-in-java) – BuZZ-dEE Jun 24 '15 at 21:21

9 Answers9

35

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.

And the test becomes:

if (SystemUtils.IS_OS_UNIX) {
    ...
}

Simple, effective, easy to read, no cryptic tricks.

ATom
  • 15,960
  • 6
  • 46
  • 50
Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
  • @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. – Pascal Thivent Jul 19 '10 at 22:46
  • 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 Jul 19 '10 at 22:59
  • @Anders: Thanks for the feedback and clarification, I get your point (and I can agree now, the javadoc is not good). – Pascal Thivent Jul 19 '10 at 23:01
  • Good idea indeed, so upvoted. But wouldn't using *SystemUtils.IS_OS_WINDOWS* be easier? – saygley Apr 27 '20 at 09:02
22

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.

David J. Liszewski
  • 10,959
  • 6
  • 44
  • 57
  • 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. – mluisbrown Jul 21 '10 at 09:15
  • 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. – Aaron Esau Apr 17 '18 at 00:03
  • @Arin. Agreed. Eight year old answer is showing it's age. I'll make it community wiki and have at it. – David J. Liszewski Apr 27 '18 at 16:36
19

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.

MikeD
  • 3,348
  • 1
  • 23
  • 36
  • 2
    I've been writing Java for years and I never noticed that function existed. Nice! – Brent Writes Code Jul 19 '10 at 15:42
  • Very good idea, but I wonder, if there there other non-Windows, non-Unix systems, that have a root "/"? – Chris Lercher Jul 19 '10 at 15:48
  • @chris_l: Most non-Windows, non-Unix systems are built as research projects for a specific purpose and a specific language, like Amoeba (Python) and House (Haskell). It feels like a cop-out answer, but I'm going to venture a guess that most of them don't have a built Java VM. That caveat aside, I would have to agree with David Thornlay's comment on the question w.r.t. testing for a particular feature rather than simply being Unix-like. – MikeD Jul 19 '10 at 16:07
  • 1
    I'm thinking more about mobile phones that support Java - and I'm not sure, what their system root is. – Chris Lercher Jul 19 '10 at 16:23
10

Javadoc says: On UNIX systems the value of this * field is '/'; on Microsoft Windows systems it is '\'.

System.out.println( File.separatorChar == '/' ? "Unix" : "Windows" );
stacker
  • 68,052
  • 28
  • 140
  • 210
  • Just as effective and more efficient than listRoots – sje397 Jul 19 '10 at 16:13
  • 1
    I do this all the time. It seems rather lame, there should be something more definitive, but it works. – Jay Jul 19 '10 at 16:28
  • 1
    What about the Classic (pre-OSX) Macintosh, where the separator character was a ':' ? – Steven Schlansker Jul 19 '10 at 18:12
  • @Steven: Is there even a modern JVM for pre-OSX Macintosh? – Jesper Jul 19 '10 at 18:26
  • 2
    @Jesper: Almost certainly not, but that's not the point. Are you **positive** that there are no other separators in use, and more importantly, that there never will be? Doing things like this is fraught with danger, and you're just going to run into problems down the road. – Steven Schlansker Jul 19 '10 at 18:51
  • @Steven - For cases like that - one could look at the line-separator it is only carriage return on mac, linefeed on unix and both on dos/windows. – stacker Jul 19 '10 at 18:52
6

System.getProperty("os.name"); is about the best you are going to get.

1

I agree with @Fuzzy in that I think the only way that Java intended you to be able to get that information was through the os.name property.

The only other things I can think of are:

  1. Have a shell script or batch file wrapper to launch your Java app that passes in OS information using the -D argument to the JVM. Though given your description, this doesn't sound doable.

  2. You could try to check for the existence of an OS-specific directory. For instance, you could assume the directory "/" will always exist on a Unix-like system, but not on Windows and do something like this:

    if((new File("/")).exists()) { System.out.println("I'm on a Unix system!"); }

  3. Try to kick off a Unix-specific command line command like ls and check the return code. If it worked, you're on a Unix-like system, if not you're on Windows.

All of those solutions are really just hacks though and frankly I don't really feel all that great about any of them. You're unfortunately probably best off with your original thought. Fun, eh?

Brent Writes Code
  • 19,075
  • 7
  • 52
  • 56
1

Use File.pathSeparator or File.separator. The first will return ";" in Windows and ":" in Unix. The second will return "\" in Windows and "/" in Unix.

-1

You could try to execute the uname command - should be available on all unixoid systems.

Chris Lercher
  • 37,264
  • 20
  • 99
  • 131
-2
package com.appspot.x19290;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class UnixCheck {
    public static void main(String[] args) {
        UnixCheck s = UnixCheck.S;
        String isUnix = s.unix ? "is Unix" : "not Unix";
        try {
            System.out.println(isUnix + ", devnull: " + s.devnull.getPath());
        } catch (NullPointerException e) {
            System.out.println(isUnix + ", devnull: unknown");
        }
    }

    public static final UnixCheck S = new UnixCheck();
    public static final UnixCheck TEST = new UnixCheck(true);

    public final boolean unix;
    public final File devnull;

    private UnixCheck() {
        this(false);
    }

    private UnixCheck(boolean testing) {
        String path;
        path = testing ? "/<dev>/<no><such><null><device>" : "/dev/null";
        File devnull = devnullOrNone(path);
        if (devnull == null) {
            this.unix = false;
            path = testing ? "<no><such><null><device>" : "nul";
            this.devnull = devnullOrNone(path);
        } else {
            this.unix = true;
            this.devnull = devnull;
        }
    }

    private static File devnullOrNone(String name) {
        File file = new File(name);
        if (file.isFile())
            return null;
        if (file.isDirectory())
            return null;
        try {
            FileInputStream i = new FileInputStream(file);
            try {
                i.read();
            } finally {
                i.close();
            }
        } catch (IOException e) {
            return null;
        }
        return file;
    }
}
  • 1
    it's not a good check as you could have a C:/dev/null directory on a Windows platform ... certainly not a frequent situation but it could be a pain to find out why the program does not have the right behavior in this case !! it's better to check the 'os.name' property – Donatello Nov 04 '13 at 16:01