If you’re following the tech press at all, you can’t have missed the news that Microsoft have, in partnership with Ubuntu, released bash on Windows 10.
However you might not know exactly what that means, or why you should care. Luckily I am one of the brave souls who play in the Windows 10 insiders Fast Track; which in practical terms means I get to reinstall Windows about once a week, but also means I get to play with next season’s toys today.
One of these toys is bash on Windows. This was fantastic news for me, as I’ve just changed jobs to a purely Windows company and was sorely missing the power of a proper bash terminal. But that’s too far into the story. Let’s start with what bash is.
The Bourne Again SHell, or bash, is a terminal emulator for Linux and Unix systems that is also a scripting language for the same emulator. If you’re a Windows person, think cmd or Powershell, but much more powerful and with an absolute plethora of tools to make a developer or tester’s life easier in the command line. Now this is not the first bash shell on Windows, far from it. There’s been Cygwin and GitBash for years and by and large they’ve done a decent job. But this is quite different. Cygwin and other bash shells on Windows have, until now, recompiled the binaries for their tools into Windows exes, this means you can’t just take any off the shelf Linux or Unix tool and just expect it to work, someone has to have worked at it to make it run on Windows. This version from Canonical and Microsoft is something quite different, quite special and just a little bit ironic*. What it relies on is the “Windows Subsystem for Linux” (which to my mind should be the Linux subsystem for Windows, but hey). This subsystem is essentially a compatibility layer, which takes OS calls from Linux binaries and converts them on the fly into their equivalent Windows calls.
So why is this special? It means you can take any old Linux binary for x86-64, and run it, assuming the dependencies are satisfied. Any old binary like, say, apt-get or dpkg. Now if you’re not familiar with Linux, you might not have heard of a package repository. This is like the Windows store, except really good and people use them. Canonical release Ubuntu, and Ubuntu has an absolutely massive set of packages in their repositories. This version of bash has access to those repositories.
This is like adding tens of thousands of tools to Windows, in one go.
So, who cares? It’s not like you needed these tools before, why do you need them now? Well I care, I care a lot. I care enough to write this blog post. Here’s why. These tools are industry standards, and they do things you might not have believed possible. The core philosophy of Unix is to do one thing and do it well, and these tools do exactly that. There’s things like ls, which is vaguely analogous to dir on Windows. It lists the files in a directory, so far so humdrum. Then there’s mv which moves files, just like Windows’ move. Nothing to get excited about here. Then there’s cat, which displays the contents of a file, just like type on Windows. But then, then we can move on to more interesting utilities, like grep, which searches for a pattern (and it can be a regular expression, a sentence, a string or even just a particular number) and shows you where it found it. There’s sed, which is a Stream EDitor, that looks for patterns and changes what it finds. So far, nothing earth shattering.
But bash has a trick up its sleeves, it’s a simple trick, but it’s an absolute corker. You can take the output from one command and use it as the input for another, and then the output from that command can be used as the input for another. So you go to your photos directory and you have a look around. You type ls
and get back a list of all the files in that directory. But you’re only interested in ones you took with Tony the Tiger, you remember naming those Tony_tiger_XX.jpg where XX is a number. So you add the pipe “|” to the end of the ls command and then add another command,
grep Tony_tiger
. This gives you the command
ls | grep Tony_tiger
and it’ll only list the files that start with Tony_tiger. But then you want to move them to another folder, say a Tony_Tiger folder. So you make the folder,
mkdir Tony_Tiger
(same command as on Windows), then you start to get creative with something called xargs. xargs takes standard input and uses it as a variable in a command. So to move all files with Tony_tiger to the Tony_Tiger directory, you can use this command
ls | grep Tony_tiger | xargs -I{} mv {} Tony_Tiger/
(You can actually do this with the metadata and rename on the fly rather than file names using another utility, but it’s too involved for this explanation, though infinitely more useful)
So while that example was fairly facile, you can see that with this piping, you can achieve some remarkably powerful effects with a very concise command, very quickly and efficiently. Now I know some purists out there are going to say that Powershell can do the same thing, which it sort of can. But for me Powershell doesn’t have the plethora of tools available, not all of its tools work in stream mode (dir, for example blocks, so it has to finish dir before it’ll release the results to the pipe), also it works in objects not text, which makes things a bit different.
So now you know what bash is, why you might want to use it and a little bit about how it works. Now let’s talk about the actual subject of the post, bash on Windows 10.
I’ve been playing with it for a few hours now and I’ve found some of the limitations of this new bash. As it stands there are swathes of the standard Linux file system missing or not mounted. The reason for this is that Windows isn’t Linux, so a lot of the layer is faking things that don’t exist. The file systems are completely different, how they treat things is completely different. Linux sees everything as a text file, sort of, so you plug a usb stick into your machine and suddenly your /dev/ directory has a ttyUSB0 file. Windows doesn’t exactly work like that, it doesn’t have a central store of files representing every piece of hardware attached to the system. Linux stores active process and system information in /proc, Windows doesn’t have that exactly. Linux stores executables (or symlinks to those executables) in /bin or /usr/bin (or indeed in /usr/sbin), Windows leaves the executables in various folders in Program Files along with the data they rely on. The two systems are very different, so not everything works.
I can’t do anything that requires netlink sockets, so I can’t ping, I can’t see my IP, I can’t do a lot of file system based stuff, like locate or df -h. These things simply don’t work, the systems to support them simply aren’t in place.
Programs like elinks (a terminal based web browser) and tmux (a Terminal MUltipleXer) don’t work quite as expected.
There’s no X server, nor even a Mir server. This means there’s no graphical utilities available. (Though I’ve seen someone use cygwin’s x server to run Ubuntu bash utilities already. Which is awesome, but not ideal)
What does work?
One hell of a lot. The mere fact that I can use standard bash tools on the windows file system means that I can suddenly have some handy scripts that will do a lot of heavy lifting for me. There’s cron, so I can schedule these scripts to run at certain times and most importantly, there’s the entirety of the repositories.
wget works, curl works. So while I can’t ping a website, I can still grab its information. Python comes pre-installed in both 2.7 and 3 versions. An SSH server’s installed, which is about the most monumental thing ever. Cygwin’s had one for years but it’s been quite ropey in use for me, and very slow. I can get git and it’s about a zillion times faster than through gitbash or cygwin in my testing. It’s got incidental little tools like curl and wget and awk and sed and… well it’s full of all the things I’ve taken for granted in the last four years where I’ve mainly been using Linux.
Is it perfect? Nope. Is it a replacement for a dedicated Linux machine? Certainly not.
Is it worth it? Yep. It removes one more layer of friction between a Windows machine and Linux machines. It makes it so you can ssh into your raspberry pi in a cmd prompt happily. It means you can use editors that format line endings properly. You can cat and grep files and search folders for strings based on regexes. You can do so much today that you could not do last week and you can do it in a supported way.
Do I recommend it? It depends. If you’re used to Linux utilities, but you work in Windows? Yes, yes, yes a thousand times yes. If you want to learn some Linux commands without the hassle of dual booting or the overhead of a VM, it’s definitely worth a go. If you never venture into the command line anyway, it’s not going to add much to your world, probably best to let it slide by. If you want a full Linux system with every possible utility at your fingertips? Nope, it’s not even close, but I hope it’ll get closer.
The thing to remember is that it is quite definitely a work in progress, nothing is quite finished and there are rough edges everywhere you look. It’s an amazing first step though and I am really looking forward to using it until the end product.
*It’s ironic because for decades, Linux has run Windows executables using something called WINE (which stands, recursively, for Wine Is Not an Emulator). WINE is a compatibility layer for windows programs on Linux. It’s the exact mirror of this Windows Subsystem for Linux.