I'm Marnanel, and this is my blog. Well, sort of. It isn't timely like a blog, and I don't expect you to subscribe to the feed (though I won't complain if you do). Rather, treat it as a quick trot around my mind, a chat over a pint in the pub, assuming you'd be caught dead talking about software in the pub. You should start here.

Thursday, May 24, 2007

It's the shell playing tricks behind your back

I am so old... gather round, children... I am so old that when I first started using PCs, Windows 3.0 hadn't come out yet. I played with Windows 2 at school, but let's face it, it was pretty dreadful. Every time when I logged out, it told me "This will end your Windows session": I actually cheered. So, though the Mac and Amiga users looked down their noses at us, we ended up using the DOS prompt a lot (and we was happy!)

If you don't know much about using the prompt, the idea is that you type the name of the program you want to run. So to run the program PRINT.EXE I could type:

> print

But if you want to tell the program to do something-- especially, if you want to tell it to work on a particular file, you can give it more information, or "parameters". So to tell PRINT.EXE to print a bunch of my files, I could say:

> print shopping.txt homework.txt laundry.txt

If those were the only three files ending in .txt I had, I had a shortcut. I could say:

> print *.txt

Now, I used to hack around writing my own programs in those days too, and I knew that when PRINT.EXE was run and it asked what it had been told to do, it was passed "*.txt". It had to go off and search for all the .txt files itself.

Then I went to college and everything in my world became different: not least, in that I got myself hooked on Unix and spent most of the day typing things into a DEC VT220. In Unix, you can print out all your .txt files using the lpr command (Unix commands are often as obscure as that: it stands for line printer). But if I typed

$ lpr *.txt

then when lpr started up, it would be given the names of all the text files by the shell (the program that you type commands into). It wouldn't have to search for them. It would be exactly as though I'd typed

$ lpr shopping.txt homework.txt laundry.txt

So there wasn't every need for every single program to include the searching code to turn *.txt into a list of .txt files in the current directory.

But it got cleverer, because now that the code only lived in one place we could do all sorts of fun things, not having to rely on every program out there to get it right. We could perform regular expression-like antics: say we wanted only to print all the files whose name began with S, T, or U:

$ lpr [stu]*.txt

That's one of the things the shell does behind your back, but there are others. On Unix systems there's a concept of a "home directory" where a user keeps zir own stuff. The directory is conventionally written with a tilde: ~firinel for firinel's home, ~ for your own, and so on. Well, pay no attention to the man behind the curtain: that's the shell, too. If I write

$ cat ~/dragon.txt

and my name is marnanel, it will turn into

$ cat /home/marnanel/dragon.txt

before cat even sees it. This is a cause of grief for a lot of people first getting into programming, because they attempt to open files called "~/myfile.txt"[1] and find it's not there: it's the shell which is playing tricks behind your back.

[1] But there are ways of getting the effect. In Perl you can use the glob builtin function:
open(STUFF, glob('~/myfile.txt'));