Chris Bailey

A UNIX–like experience on Windows

Preface: why?

I've had a lot of experience developing software and generally using several different operating systems and tend to switch between them quite often.

I've grown to adore features that Linux/BSD users take for granted, such as having easy access to software via package managers, a first class CLI experience, and the ability to tweak your OS to your hearts content.

However, as someone who has used Windows as a development environment and as a general OS for my workstation and Surface Pro (whose Linux support is shaky at best), I also appreciate the just-works aspect, the lack of driver issues and the fact that I don't need to dualboot or play with PCIE-passthrough + Virtualization to run Windows-exclusive software.

Where to begin?

On a high level, theres a bunch of different options you have, each with their own pros and cons. I'm currently using technology such as Erlang, Elixir, Docker, Kubernetes, as well as a plethora of CLI tools so I'll focus a large part of this post on things like getting a good UNIX–like shell and terminal emulator setup.

On the other hand, we'll also look into more niche and fun things such as running graphical applications and achieving a more UNIX–like user experience as well, since that stuff is more seldom spoken of.

A decent shell

So my number one priority when setting up a new machine is to configure my shell and terminal to my liking. Aside from the fact that I'm currently mainly using more backend-oriented languages, I also use vim as my preferred text editor so I find myself pretty much living in the command line.

This is the area where you have the most choices on Windows. Before we start looking at any of the UNIX–like choices however, you should ask yourself if theres any real need to choose one.

While the default shell is fairly lackluster (as well as its terminal emulator), if you're primarily working on stuff like C# or finding yourself living in an IDE such as Visual Studio, you may not get much benefit from switching.

Powershell is also a very legitimate choice. I've used it for a few small things here and there, and combined with Chocolatey, it makes a pretty nice combination for pure Windows power users.

However, I don't personally use it outside of a few one-offs simply because whilst its very powerful, I find certain things quite slow and I'm also much more used to a standard UNIX–like CLI experience.

I've used the following UNIX–like shells on various flavours of Windows over the years, and I'll outline the advantages and disadvantages to each approach. The main thing is that they all differ in terms of cohesion with Windows, and compatability/neccessary workarounds with non-standard or non-userspace utilities.

Cygwin

Cygwin is the oldest approach to providing a UNIX–like shell I have used. It essentially just provides a library which is used to implement POSIX system calls as the equivalent Win32 system calls.

The downside of this is that any software you actually want to run has to be compiled against the provided library. To work around this however, there is a huge repository of software which comes bundled with Cygwin and can be installed by running the graphical installer.

There is also plenty of support from the community, including, importantly: third party package managers to make installing software via the official repositories simple: apt-cyg repo

When installing Cygwin, I try to install only the very base pre-requisites needed for apt-cyg so that I can configure and install Cygwin packages entirely from the shell after the fact.

To do this, you'll ideally want to install:

Once you've done this, head over to the apt-cyg repo and follow installation instructions. You can then pretend you're living in a UNIX–like shell and install software via the following incantation: apt-cyg install vim rxvt ...

Cygwin's biggest major advantage is also its biggest disadvantage: it isn't UNIX. Cygwin treats Windows as a first class OS and you can just run Windows software from the shell. Your hard drives and external devices are mapped by default to /cygdrive/ (i.e. C:/ maps to /cygdrive/c), and it has full access to the Windows API. You can even hack readline support into non-readline utilities (such as the Windows version of the Erlang shell) by wrapping it with rlwrap.

Recompiling software explicitly for Cygwin can be fairly painful though; you'll be travelling on a road not many have travelled on before if you dare step beyond the standard package repositories. I ended up using a mash-up of Windows applications in the command line alongside Cygwin ones.

Because certain POSIX system calls don't map well to Win32 system calls (like fork), certain things can be quite considerably slower too. Support for things like Docker (which needs a Linux kernel to function) won't work either — you will have to use Docker for Windows and live with the heavyweight virtualisation cost.

I also haven't had much success with the x64 version of Cygwin, but the x86 version performed fine.

In short, if you don't need utilities such as Docker, you're just trying to have a more UNIX–like command line experience, value the amazing interoperability, or you don't run Windows 10 then definitely try Cygwin.

WSL

WSL (Windows Subsystem for Linux) is a fairly recent approach to providing a UNIX–like environment to Windows, developed by Microsoft themselves.

WSL is amazing and checks many of the same boxes Cygwin checks. Having used Cygwin on literally every Windows machine I used, and having used it for years professionally, the advent of WSL made me switch over immediately — though only because my particular usecase doesn't involve cross compiling to Windows or anything like that.

The most immediate downside is that WSL only supports Windows 10. This might not be an issue for you, but if you're not using Windows 10, your best choice is Cygwin.

Otherwise, you can install WSL by enabling the feature via Powershell (make sure to run as admin):

Restart your PC, then head on over to the Microsoft Store and install your distribution of choice. I personally go for Ubuntu, but you can choose from a handful easily. The community has also created tools to allow you to install other distributions such as Arch Linux. I haven't used these tools however, so I don't have much of an opinion on them.

Once installed, your distribution of choice will be added to your start menu and you can launch it that way. When you launch WSL, you'll essentially feel as though you're in a fresh install of whatever distribution you chose.

WSL works somewhat similarly to Cygwin in that it provides a POSIX system call translation layer. The main difference is that applications installed in WSL are real Linux binaries meaning you lose a little bit of interoperability but you gain much more out-of-the-box support.

It also means that it shares some downsides with Cygwin, such as the slowness of certain system calls such as fork.

WSL essentially feels like you're in a virtual machine, except you can also launch Windows applications and view/edit your Windows filesystem too.

The major downside about this is that WSL doesn't treat Windows as a first class citizen. You should never, ever use Windows applications to modify/write to your WSL filesystem as you can corrupt file attributes and the like since Windows applications don't know about WSL at all, though you can work around this by using WSL to work out of your Windows filesystem. You can find your C:/ driver mounted to /mnt/c.

Because no Linux kernel is present either, you'll have to resort to running Docker for Windows as opposed to just being able to run Docker in WSL. A few other things don't work yet but WSL is still being developed.

WSL 2

WSL 2 is another Microsoft development, which as far as I understand, is being worked on in parallel with WSL.

WSL 2 is interesting because it gives us a real Linux kernel running in Windows. The way it does this could be seen as a downside however: its a Virtual Machine.

To install WSL 2, you can simply follow these steps:

  1. You need to be running Windows 10 build 18917 or higher since right now its a technical preview.
  2. You need Hyper-V enabled:
  3. You need WSL enabled:
  4. Then, assuming you have Ubuntu installed already via the Microsoft store:

The cool thing is, we run WSL 2 as thought it was the original WSL. I don't really feel or notice any real difference. The Virtual Machine which backs WSL 2 is super lightweight and automatically scales as you consume and free up resources. Because we have a real Linux kernel now, we can also run things like Docker without any workaronds!

You'll find WSL 2 is a lot faster at certain things because Windows Defender no longer scans new files being created / modified and all system calls are running against the kernel.

The biggest downside that presents itself is, however, that it is a Hyper-V Virtual Machine. Because Hyper-V is a Type 1 hypervisor, what I understand happens is:

On the plus side, your Linux filesystem is mounted over the network into your Windows filesystem, so you can edit and create files in both directions now. I wasn't able to make symbolic links between filesystems however, which is a lost feature between WSL and WSL 2.

A really minor downside if the first time you launch a WSL 2 shell, it'll take a second to start up as it is initializing the Hyper-V virtual machine. It literally only takes 1–2 seconds however so its not a major concern for me.

In short, I think WSL 2 is the best choice to me personally since its everything WSL could do, but more fully fledged with the loss of only a small amount of interoperability which is fine if I'm living in WSL anyway.

A decent terminal

Now that we have a decent shell, we just need a decent terminal to back that up. Microsoft has improved the standard Command Prompt in newer Windows 10 versions but the experience is only really great with the standard WSL, plus the standard hotkeys are a little esoteric.

This is the part creating a good development environment that is most difficult for me, since there really aren't all that many options and literally every one of them have some pretty serious trade offs...

I've used the following extensively, and have a few opinions:

MinTTY and WslTTY

This is the default option if you go the Cygwin route, and honestly the terminal emulator itself is really, really good.

Whilst just about everything is slower than the Command Prompt experience, it is probably one of the fastest terminal emulators on Windows and supports a lot of customization options.

Some things to point out include the fact that you have full mouse support, so moving between panes and windows in tmux is painless. Whilst not a hard requirement for me, its a nice to have feature and as we'll get to below, its always better to have this fully implemented than like on some other terminal emulators.

One thing that seems missing is the ability to add padding to the terminal window itself; I personally find having no padding makes the first character of the terminal really rather hard to read, and whilst if you google around, you can find a setting to add padding, I can only manage to add a meagre amount of pixels before mysteriously being unable to add more.

If you're using this with WSL (which works great) or WSL 2 (which might be problematic right now? I'm not sure), you'll probably want to install wslTTY instead of just the base minTTY.

Oh, and if you're a powerline user or you like fancy emoji, I don't think MinTTY supports unicode... so that might be a deal breaker for you.

ConEmu

I see a lot of people who don't like minTTY or wslTTY go for ConEmu or one of its derivatives, but I don't actually understand why.

What ConEmu gives you is a hell of a lot of customization opportunities. You can increase terminal padding (yay!) and you can set a lot of nice-to-haves like terminal dimming and transparency options. You also get native tabs, multiple profiles with different color schemes and different launch configurations so that you can have different settings for different shells.

The thing is, whenever I try using ConEmu, I get a lot of quirky behaviour that I'm unsure the cause of. Resizing the terminal window can be really unresponsive and laggy, mouse support is hit and miss (especially on WSL).

There are many arcane incantations for setting up launch profiles for certain shells and some of them will let you use certain features (like mouse support), others will give you partial support and others will freeze up and act strange. Whenever I've used ConEmu it always feels like trial by fire.

Native CMD and Powershell support is nice though, and if you're looking for a better terminal emulator for Windows alone, this is a good choice.

Cygwin's rxvt

This one is a little weird, since it is so close to perfect, but has two major downsides in my opinion.

When you're installing Cygwin, you actually have the choice of installing rxvt which is the base of my preferred terminal emulator in a real UNIX system.

Rxvt gives you full XTerm support and gives you mouse support*. It is also blazing fast. Usually when you want to run Linux Terminal Emulators on Windows (which we'll get to in a moment), you need to run an X Server implementation. I'm not sure how the Cygwin contributors did this, but the native Rxvt application that comes with Cygwin doesn't seem to need one, which makes it a strong native choice.

You can configure rxvt by writing configuration options of your ~/.XResources file. This is great in some senses as you can use your Linux dotfiles with this, but its quite difficult to configure the font with rxvt since its a weird mismash of Windows and Linux.

The reason I can't really recommend this terminal emulator however, is because as far as I know, its Cygwin only. Its not possible to configure rxvt to work with WSL or WSL 2. Alongside this, since this is the standard rxvt package and not rxvt-unicode, it doesn't support unicode.

It is possible to run Cygwin's rxvt-unicode package, but that'll require an X Server unfortunately.

A flaw it shares with rxvt-unicode is the fact that mouse support is only partially implemented. Because rxvt implements mouse support via the DECSM 1015 protocol which only supports mouse clicks up to the 220th column. There are patches to rxvt which implement the SGR mouse protocol (DECSM 1006) to fix this issue, but that only applies to the X Server dependant variant and in my mind isn't worth the hassle unless you're on a real UNIX system.

Linux Terminal Emulators

This was my preferred choice until recently. You can run whichever Linux terminal emulator you want on Windows so long as you install an X Server.

I've only ever used VcXsrv and X410 as Windows X Servers, and I think they're more or less identical feature wise, so I don't have too many opinions about that. I personally use VcXsrv because it redraws your X Buffers on resizing and such while X410 waits until you're done resizing to refresh the buffer. X410 seems slightly faster but also costs money. Any X Server for Windows will do.

Once you've got an X Server installed, you can set it up to be in single window or multi window mode. Single Window essentially creates a new window which acts as the workspace on which X Windows will be drawn. You can often fullscreen this window and live inside a Linux Desktop Environment or Window Manager like Openbox or Gnome.

I've found performance to be a little slow at higher resolutions when using Single Window modes and because I value the transparency and interoperability, I use Multi Window mode which essentially intergrates your X Windows with your native Windows decorations—essentially as though Windows was your window manager.

You'll need to set the DISPLAY environment variable of whatever shell you're using to point to your X Server, but then you should be able to launch applications as you normally would on an equivalent UNIX system (i.e. pcmanfm& or xterm&)

The really nice thing is you can also now share the clipboard between applications like vim and Windows, since most Windows X Servers essentially implement a XClip polyfill.

If you're on a higher resolution display, you might have some DPI issues, but you can often fix these easily if you search for the issue online.

If you're using WSL or WSL 2, and you don't want to launch the standard wsl.exe prompt to be able to launch your X applications, you can create Visual Basic scripts to do this for you, using the following snippet:

Windows Terminal (Beta)

I don't have too much to say about this at the moment because it is still in beta, but I evaluated this emulator and I immediately switched to it.

It supports unicode, is super fast, super configurable (yay! terminal padding!), is configurable via changing a JSON config file which you can keep in version control, is fully native and supports multiple configurations for different shells. It even has tabs.

I noticed that it doesn't yet support mouse clicks, but as it is in beta, I can live with it. Again, I'd rather no mouse functionality than a partial implementation like with rxvt.

I've been using it for a month or so now and I'm really happy with it. Certain more esoteric characters (such as the ones drawn by nvim's floating windows) can cause some glitching but apart from that and the lack of mouse support, its everything I could want—and its still in beta!

UNIX–like UX

Hopefully now, we have a decent shell with a decent terminal emulator. Outside of setting that up however you want, be it setting up your text editor (such as vim, emacs, etc), shell (like zsh or fish), we're pretty much done.

I won't suggest how you should go about configuring your own environment, but if you're interested about what I use, you can check out my dotfiles.

UX–wise however, you might find Windows to be a little jarring. Whilst Windows 10 allows us now to have real virtual workspaces, we're missing a few bells and whistles which we can easily attain. I'll outline a few important ones below:

Moving and Resizing Windows

On UNIX–systems, especially when using a Window Manager such as Openbox, I've grown accustomed to being able to hold the Alt key and left click drag open windows to move then, and Alt right click drag to resize them.

You can have this functionality on Windows in a few ways, but the most configurable and easy to use way that I install on all my Windows PCs is an application aptly named AltDrag.

It also supports binding actions to the middle mouse button and is pretty extensible and light weight.

Hotkeys

I use a tool called AutoHotkey to allow me to implement hotkeys for launching applications.

You essentially write a .ahk file with a simple (though archiac) DSL to hook keypresses and trigger events, such as launching Firefox with the following hotkey:

Personally, I have a lot of AutoHotkey scripts running which let me move, hide, and resize windows, as well as some more complex functionality to moreso emulate a Linux Window Manager.

Window Manager

If you really want, there are a few alternative Window Managers you can install to tweak your setup even further.

Back when I was using Windows 7 and 8, I would use a Window Manager called BBlean or BBzero which was essentially a Windows version of the Linux Window Manager called BlackBox (which is pretty similar to Openbox).

With a bit of tweaking, and accepting random crashes (which is why I don't use these window managers anymore), you can get BBzero working decently well under Windows 10.

BBlean and BBzero come with their own task bar implementations, workspaces, hotkeys, window decorations, interface creation plugins and more. Honestly they're pretty fun to use but the sad state of Windows 10 compatability means I can no longer really suggest these. High-DPI displays are also a no-go.

If you're really adamant about having your Windows 10 installation look like something you'll see on certain subreddits catering to highly customized Unix environments, then you can definitely achieve that look either through running your Linux applications through an X Server or using AutoHotkey and application-specific configuration to create a seamless look.

If you're interested in my setup, you can see a screenshot of it below:

My Setup

Which was done through a combination of hiding titlebars on certain windows with a custom AutoHotkey script and a custom Firefox userChrome.css file.