Recent WSL Releases: wslinfo
In recent WSL releases, the wslinfo command has been added and can be used to check certain features of WSL from within the running distribution. There are several different features that can be used here:
In WSL pre-release 2.0.4, the /usr/bin/wslinfo command was added with the --networking-mode switch. /usr/bin/wslinfo is always a symlink to the WSL-injected /init. You can:
- Check for the binary and whether it is a symlink.
- Run the
wslinfo --networking-mode command and confirm a non-zero exit code.
In WSL pre-release 2.2.3, wslinfo --wsl-version was added, which will report the WSL version number. This can also be used, not just to check whether we are inside a WSL distribution, but also (obviously) the version number.
Sometime between 2.2.3 and 2.6.0 (the first open-source release of WSL), --wsl-version was deprecated (it is still available), and wslinfo --version was added. Unfortunately, the addition of the --version switch was never (that I can see) documented in the release notes, so it's tough to tell how far back it goes.
(credit and thanks to @ironsand for suggesting the wslinfo command via original edits)
Plan9
Ironically, three years later I'm noticing that a few minutes after I wrote this answer originally, I answered another question here) about the plan9 process. This is also a symlink to /init, as with wslinfo, and can probably be used in a similar way (check the existence of the binary and symlink) for much older releases.
Other methods for older releases
Each of these detection methods could cause false-positives or false-negatives in certain situations. That said, if you are just doing this for your personal config files, then you probably have a pretty good idea about whether a given method will work for your system or not.
Some various methods, with their pros and cons:
The presence of /proc/sys/fs/binfmt_misc/WSLInterop is a pretty good indicator that you are on WSL. This is what Ubuntu's Snapd project used as its detection mechanism at one point (it may still). This file exists under both WSL1 and WSL2 by default. Even when Interop is disabled via /etc/wsl.conf, this file will still be created by WSL at startup.
Caveats:
The use of Systemd in WSL can in some situations reset the binfmt entries and suppress the creation of this file.
Of course, a binfmt_misc entry could be set up with the name WSLInterop, but that would be extremely pathologic, leading to a false-positive test.
Also, it is possible to override the name of the Interop, as mentioned in my Ask Ubuntu answer here. This would be an unusual case, but we used it to thwart the Snapd WSL detection temporarily while a bug was being fixed. This creates a false negative, of course.
In a war of escalation, you could "thwart-the-thwarting" by grepping for the magic 4d5a in that directory, but that might be going a bit far ;-)
As @MBehrens mentions, the default kernel name under WSL contains the string "Microsoft" (or "microsoft", depending on the release). Using uname -r or /proc/version) can be used for detection.
Caveats: Other systems may (I'm thinking Azure) use a Microsoft-built kernel, which could create a false positive. And it's possible to build a custom kernel for WSL2 with a different name, which would create a false negative.
You could even just check for the environment variable $WSL_DISTRO_NAME. This variable is injected into the WSL environment automatically.
Caveats: You could always (pathologically) create this variable name on any system, leading to false positives.
More importantly, there are cases when this variable will not be available, such as if you su - $USER.
There are certainly more (e.g. see if $(which powershell.exe) is executable), but the above should give you some idea of the various approaches.
/etc/wsl.confdoesn't exist on my WSL./etc/wsl.confon a pure-Linux system, causing false-positives. So the OP was asking for better options.