Windows 10 now includes an Ubuntu bash shell!

Windows has shipped with Powershell and Command Prompt for years, but neither is a bash shell suitable for modern web development.

Even with third party options like Cygwin and Git Bash, the effort required to keep bash tools working made Windows a no-go zone for many frontend devs.

With that in mind, it’s not totally surprising that Windows 10 now includes an Ubuntu bash shell.


The shell is an opt-in beta feature called Windows Subsystem for Linux (WSL). It’s often referred to as “Bash On Ubuntu On Windows” and occasionally as LXSS. It came about in response to developer feedback (see the start of the video).

WSL is not a virtual machine or emulation, it’s Ubuntu’s user-mode binaries running on a Linux-compatible Windows kernel. The WSL FAQ describes it as a tool for web developers and those who work on or with open source projects.


Screenshot of WSL showing bash version and uname of Linux

So is WSL really a proper bash shell? Yes! It runs GNU Bash 4, identifies as Linux and even runs with the Ubuntu logo.

The slightly longer version is yes, but since it’s a beta not everything works yet. Also if you haven’t used Linux before, you’ll probably need to learn a couple of things like setting up SSH agents and using apt-get.

Getting started with WSL

Microsoft provide a detailed installation guide so I won’t replicate that. One thing to note is some people report that WSL clashes with Git Bash.

A few tips for WSL:

  • Your WSL home directory displays as /home/(username)/, with the full location being C:\Users\(windows username)\AppData\Local\lxss\home\(bash username)
  • Drives are accessed under /mnt eg. cd /mnt/c
  • There is a definite line between the WSL-only file system and the shared WSL/Windows file system. If you use the Windows GUI to modify a file located under Local\lxss, it will disappear in WSL. If you work 100% inside bash, this probably won’t be an issue; but if you move between the CLI and GUI it will. See suggested configuration for a workaround.
  • WSL has its own symlinks which can’t duplicate or conflict with Windows symlinks. I had an existing Windows symlink to Dropbox (for use in Cygwin) and had to make a Dropbox2 symlink in WSL.
  • uname -s returns Linux, so if you need to explicitly identify WSL, grep /proc/sys/kernel/osrelease for Microsoft.
  • Remember to save everything with unix line endings. If a script breaks, check the line endings. You may want to install dos2unix.
  • WSL is currently based on Ubuntu 14.04, which means all its tools (eg. git) are correspondingly old. It looks like a 16.04 upgrade is coming soon.
  • WSL will prompt for updates, eg. 8 packages can be updated. 7 updates are security updates. when you open up a session. To handle this, run sudo apt-get update

Suggested configuration

  • Unless you work 100% in the CLI, set up a dev directory outside WSL’s file system. This avoids the disappearing file problem, so you can move and edit files in the Windows GUI. My dev directory happens to be /mnt/f/dev/ but you can put it pretty much anywhere so long as it is not inside C:\Users\(windows username)\AppData\Local\lxss\. Avoid C:\Users\(windows username)\ if you already use another shell which stores configuration files in that location (eg. Git Bash).
  • Remember any home-directory configuration like ~/.bash_profile, git config and SSH keys need to be done inside WSL, eg. with Vim or Nano; by echoing into the file; or running commands that handle the edits for you.
  • To make life a bit easier, my real bash config lives in Dropbox and so /home/username/.bashrc only has one line: source /mnt/d/Dropbox\ \(Personal\)/path/to/.bash_profile. Note that WSL will execute .bashrc but not .bash_profile when you start a session. You can always source the profile from the rc file if you want to.
  • Some people have symlinked ~ to their dev directory, making it more of a reconfigured home directory. I just have cd /mnt/f/dev/ at the end of my .bash_profile – really simple but it works.
  • Generic advice that still applies: use version managers to install things like Node and Ruby – the apt-get versions are old.

2017.04.14 Update: now that interop works, you might want to add a couple of useful aliases:

  • alias open="explorer.exe" - this will open files or directories the same way as open on OSX or cygstart in Cygwin.
  • alias s='"/mnt/c/Program Files/Sublime Text 3/subl.exe"' (note the extra quotes to get around the spaces in the file name). This makes it easy to open a GUI editor from WSL with minimal context switching.

Coming-from-OSX gotchas

  • Keychain handles your SSH key passwords (eg. for git), but Linux doesn’t. You will need to set up an SSH agent and enter your SSH key password(s) once per session. If you don’t actually need this every session, include this in your bash profile:
    startssh() {
    eval "$(ssh-agent -s)"
    and then you can just type startssh when you need it.
  • If you use git bling scripts to show branch and dirty status in your PS1, you’ll need to update the string it uses to determine git-dirty status. OSX git says working tree clean but Linux says working directory clean. Potayto, potahto.
  • Note OSX is still on Bash v3, probably because Bash v4 uses the GPL license (which Apple won’t ship). Most of the time this doesn’t matter, but if you start using snippets and commands from Linux sources you’ll run into Bash 4+ things like brace expansion that won’t work on OSX.

Working with WSL

To put WSL through its paces, I tried a few things:

  • set up my usual bash config and customisations
  • SSH into a remote system
  • clone a git repo and push changes
  • create a simple Node/Grunt static site
  • view the site with python -m SimpleHTTPServer 8888

Screenshot of WSL running grunt tasks

Nearly everything worked:

  • Bash basics like file system navigation
  • Bash profile, PS1, exported variables, SSH, SSH agent and scripts
  • Node: NVM, NPM and Grunt
  • Grunt tasks: grunt-contrib-clean, grunt-contrib-copy, grunt-contrib-pug, grunt-contrib-uglify, grunt-sass, jit-grunt, time-grunt
  • Python: SimpleHTTPServer
  • I also installed Ruby with RVM, although I haven’t done anything with it yet

Update June 2017

A few things didn’t work in the August 2016 beta:

As I said at the time...

Given the energy and pace of the project, the yet is intentional. WSL was more alpha than beta on the Windows Insider builds that came before the Anniversary Edition; and each update steadily worked through problems users were reporting on github. There’s good reason to expect things to actually get fixed.

...and it turns out this optimism was well placed. As of the April 2017 Creators Update of Windows, all three are done.

For interop, the Windows exe file must be visible in your path (echo $PATH), or you can alias the full path (alias s='"/mnt/c/Program Files/Sublime Text 3/subl.exe"'). The caveats remain that you should not use a windows application to edit files inside the linux file system; but the workaround listed above does still work.

open . still doesn't work as you might expect; but explorer.exe . does; so a quick alias and away you go (alias open="explorer.exe").

Last thoughts

It’s great to have a vendor-supported bash shell in Windows 10. I hope the WSL project’s energy and optimism stays as high as it is now. If you’re interested in WSL at all, now’s a great time to get in there and try it out.