Idiomdrottning’s homepage

Three Different Kinds of Commands

echo, meet which

Remember how echo had the simple job to print back anything you told it? It’s time to meet another friend, which. It’s more specific in what it wants to hear from you. If you tell it the name of another program it tells you how it knows that program. What does that mean? Let’s look. I’ve only told you about echo so far, so let’s ask which about echo like this:

$ which echo
/bin/echo

That means that it knows echo is in the /bin directory, or at least that’s where it is here on ellen, my computer. It might be different on yours.

Here, bash reports the same as the old Bourne shell, that it’s in /bin. On zsh, it looks like this:

ellen% which echo
echo: shell built-in command

So some programs, or “commands”, are so familiar to the shell that they’re built in.

which, where are you?

Let’s ask which about which.

$ which which
/usr/bin/which

So on the classic Bourne shell, which is in the /usr/bin directory. The same is true on the bash shell, while zsh also has a built in which. See:

ellen% which which
which: shell built-in command

To round this out, I’ll show you what which reports in my zsh here on my computer when I ask it about the three shells I’ve mentioned so far.

ellen% which sh
/bin/sh
ellen% which bash
/bin/bash
ellen% which zsh
/usr/bin/zsh

Again, I’m typing what follows the %-signs, and zsh is typing the rest back to me, both the prompt ellen% and the answers to the questions it got from which.

So which expects the name of programs and won’t understand any other words.

ellen% which way to the top
way not found
to not found
the not found
/usr/bin/top

It’s not smart. It believes that way, to, the and top are the names of programs, not parts of a sentence. Turns out it’s actually right about top, though. It’s a classic program that shows you how much work the computer is doing right now. If you happen to start it and don’t know what to do, you can press q to leave it. And what do I know, maybe you have programs named “way”, “to” or “the” installed? I didn’t.

That’s not to say that echo is smart about what you tell it either. It can parrot it back, but it can’t “understand” it.

Comments, and more about prompts

So far, I’ve been pretty careful to only use words with plain letters in my examples of “talking” to the shell. Even though I’ve asked questions like “Can I just type anything” and “which way to the top”, I haven’t even used a question mark.

The reason for this is that the shell itself (rather than programs, like echo or which) has a special relationship to some of the special characters like ?, *, # and a few others, especially apostrophes and quotation marks.

For example, the # symbol means something that the shell just throws away and does not pass along to the program. Like this:

$ echo now you see me # now you do not see me
now you see me

This # symbol is meant for comments to other programmers (or to yourself) rather than commands to the computer. Here’s another example, one that’s more in that vein.

$ echo A mess of pottage # Here, I wanted the computer to write "A mess of pottage"
A mess of pottage

In a shell comment, you can use the weird characters without problem. The shell knows you’re just making a comment and doesn’t try to understand.

Be careful though: symbols mean different things in different contexts. The # is also often used as a prompt for the administrator. It replaces the friendly $ or %-sign to alert you that it has the power to, for example, erase anything on the computer. That’s why it’s important to learn to recognize your prompt. Think of the shell as your eyes and ears in the computer world, and the prompt as the computer asking for your input.

ellen% echo eight days a week # Say “eight days a week”
eight days a week
ellen% # even when I'm not commanding anything, I can make a comment

…later, if I switch to the administrator account:

ellen# ← the prompt has changed from % to #
ellen# exit ←better just exit for now

These two uses of the old # are completely unrelated (and it’s only a coincidence that the two different things both show as a #). It’s strange… the comment is so safe, it means “don’t worry, this is only a side remark for other humans, the computer won’t mess anything up since it’ll just throw this part of the text away” while the administrator user prompt # means “Please be careful, remember that you have great power”.

Functions

We talked earlier about how which sometimes showed us programs that were placed in directories, and sometimes showed us commands that were built-in to the shell. There is a third type of command that the shell can use, and that’s “functions”.

I’ll show you a simple one, to start with. This is on zsh:

ellen% vegetable () {
echo I like to eat aubergines
}

Weird, right? I’ll go through it row by row. Let’s say I wanted to often have the computer write to me how much it likes to eat aubergines. I could easily ask it to say that, like this:

ellen% echo I like to eat aubergines
I like to eat aubergines

But what if I wanted to do it with just a simple command? Like this:

ellen% vegetable
I like to eat aubergines

So the first line was vegetable () {. Now, vegetable is just the name of the new command. I could’ve used any word (hopefully not a word that the computer already expects to have meaning, but I can check that with which if I am unsure). The parentheses is how we let the shell know that we’re teaching it a new function. And the curly braces, these: {}, well, they surround the list of commands that the shell should do everytime the new function is called. In this case, all I’ve asked it to do is to echo something back at me.

When using <code>zsh</code>’s built-in version of which, it even knows about it:

ellen% which vegetable
vegetable () {
        echo I like to eat aubergines
}

And I can call it how many times I want:

ellen% vegetable
I like to eat aubergines
ellen% vegetable
I like to eat aubergines
ellen% vegetable
I like to eat aubergines

This makes me happy. The computer now likes to eat aubergines. Teaching the shell new functions like this is great, because it can do many things at once.

Let’s say I wanted it to both praise eating potatoes and to tell me how it knows about echo:

ellen% potatowhich () {
echo I like some potatoes
which echo
}
ellen% potatowhich
I like some potatoes
echo: shell built-in command

The shell treats our homemade functions no different than the programs it finds in files in places like /usr/bin, and no different than the built-in shell commands either.

Before you get carried away and write hundreds of nifty functions, remember that just defining the functions at the prompt like this does not save them. Be sure to save them in a text file.