Bash 101: Working at the CLI

7574

The command line can be very intimidating to new users. Having to use the command line is one of the chief complaints and fears for a lot of users who venture into Linux. But it doesn’t have to be scary, and you don’t need to know everything to dip your toe in and find out how useful the CLI can be.

When we talk about the command line on Linux, we’re usually talking about GNU Bash. In this tutorial, I’ll show some of the basics of Bash without getting too deep into Bash’s functionality. This means that I’ll skim over a lot that more expert users already know, but try to provide a sane overview for new users who aren’t (yet) gung-ho about using the CLI.

What’s Bash?

Bash is the shell for most major Linux distributions. If you’re running openSUSE, Ubuntu, Fedora, Slackware, Mandriva, then when you are at a console or have a terminal open, you’re working with Bash. The name, “Bash” is actually modeled after the Bourne shell, a shell that was created by Stephen Bourne and distributed with Unix starting in the late 1970s. The “Bourne again shell” emulates the original Bourne shell in many ways, but also adds a number of features and runs on far more operating systems than the original.

If you’re newish to Linux, you’ve probably heard a fair amount of talk about the “shell,” but might not be entirely clear on what’s being discussed. Basically, the shell is a user interface. Shell is not synonymous with the command line. When you use a desktop environment like GNOME, a shell (in the case of GNOME, Nautilus) takes commands from the user and tells the operating system what to do. That’s a drastic simplification, but the basic idea is that the shell is your interface to the computer.

It’s a bit more than that as well. Bash also is “command language interpreter,” which is to say that it runs scripts non-interactively. The same commands that you use at the command line can be put together and run as a program.

Bash isn’t the only shell game in town, only the most popular. Most Linux major Linux distros ship with GNU Bash by default, but you’ll usually find alternate shells in the package repositories. In addition to Linux, GNU Bash is shipped with Mac OS X, and Bash is available for just about any operating system you’d want to run. Other Unix-type OSes usually ship with other shells as the default, but you can install Bash on them easily enough. Running alternative shells on Linux or Bash on other OSes is a bit beyond the scope of this tutorial, but it’s always good to know that there are options.

Running Commands

Let’s start with running a few commands at the shell. You’ve probably already had at least a little experience with the shell prompt. Usually if you’re logged in as a regular user, you’ll see something like this:

 

user@fluffy:~$

 

Most distros set up the default to display a $ prompt if you’re logged in as a normal user and a # prompt if you’re logged in as root. Some tutorials and guides show each command and the shell prompt in examples. I’ll just show the commands that you’ll be using. It’s good to remember that there’s no “undo” in bash, so be careful. You can, however, tell bash to try to prevent at least one common mistake — overwriting files. Do this using the set command:

 

set -o noclobber

 

As you probably guessed, “noclobber” tells bash that it shouldn’t overwrite existing files when output is redirected to them. When noclobber isn’t set, a command like this will overwrite the target file:

cp file1 file2

So if “file2” exists, it will be overwritten without comment. That’s how most Linux users like it. But if you’re extra-cautious, setting the noclobber option will show this:

bash: file2: cannot overwrite existing file 

If there was no “file2” then bash would happily write to it. But since a file by that name exists, it refuses to overwrite it. If you really want to overwrite it, you can add the -f (force) option to cp:

cp -f file1 file2 

I find the “noclobber” option to be annoying, but it might be a good thing to set while you’re getting used to the shell.

Running Commands

It’s useful to be able to run single commands (like vim) from the shell, but even more useful to get them working together. Most shell commands and utilities you find on a Unix-type system are meant to take input and produce output that can be used by other programs at the shell.

For example, on openSUSE I usually use the zypper command at the shell to manage packages. Sometimes I want to look for a new piece of software, and the search term produces too many results. I can combine the zypper command with grep to narrow those results:

zypper se vim | grep Editor

The | in the middle is called a “pipe” and redirects the output from the first command (zypper se vim) to grep, which then searches for the string “Editor.”

What if you want to run a couple of commands in a row? You can type them in one at a time, or you can chain them with bash operators. You’ve already seen how to use the basic pipe. Another way is to run command sequentially by separating them with a semicolon, like this:

command1 ; command2

That tells the shell to run command1 and then when it’s finished, move on to command2. You can also tell the shell to run command1 and then command2 only if the first command is successful with the “and” (&&) operator:

command1 && command2

Alternatively, you can tell the shell to run a command, and then follow up with a second command if the next command is unsuccessful by using the “or” operator like so:

command1 || command2

This can be really useful when writing shell scripts. That’s a bit beyond the scope of this tutorial, but these operators come in particularly handy when evaluating if a command is or isn’t successful.

Navigating the Shell

When you’re at the shell prompt, you have some powerful editing capabilities at your fingertips, though that’s not obvious at first.

By default, Bash uses Emacs-like shortcuts to move around the command line. This can save you a lot of time retyping things if you enter a long command like this and then realize that the first command is misspelled, or you forgot to add “sudo” in front of it:

zypper se -t pattern -r repo-oss

Do you want to retype that if you forgot to add “sudo” at the beginning? Of course not. Instead, you can type Ctrl-a and the cursor will move to the beginning of the command line. Typing Ctrl-e will move you to the end of the command line. Here’s a few of the movement commands that will save you lots of typing time:

  • Ctrl-a: Move to the beginning of the line.
  • Ctrl-e: Move to the end of the line.
  • Ctrl-k: Delete the text from the cursor to the end of the line.
  • Ctrl-w: Delete the previous word.
  • Alt-d: Delete the next word.
  • Alt-f: Move forward a word.
  • Alt-b: Move backward a word.
  • Ctrl-n: Scroll down in history.
  • Ctrl-p: Scroll up in history

We’ll get to the history stuff in just a moment. Note that the arrow keys on the keyboard usually work as well, but it’s good to know the other commands as well.

If you’re familiar with Vim and vi-like keybindings, it’s possible to tell bash to use vi-like keybindings instead. Of course, if you’re familiar with vi-like keybindings, your probably pretty familiar with the shell, too! To set this, run “set -o vi” and bash will switch to vi-like keybindings. It will start in insert mode, so if you want to use vi movements, hit Esc first.

Another useful feature is tab completion. When you’re typing a command or filename, try typing the first few characters and then hitting Tab. If there’s only one command or filename that matches, bash will automatically complete it for you. So, for instance, if you’re typing something like “command reallylongfilename” and you type “reallyTAB” bash should complete the filename. This can save a lot of time and effort typing.

Bash will also insert the last string on a command line in the next command if you use Esc-. If the last command was something like “mkdir directoryname” you can then type “cd Esc-.” and bash will swap in “directoryname” to your command line.

Multitasking and Jobs

When using a desktop environment like KDE or GNOME, it’s easy to see multitasking in action because you can watch several programs running at the same time. You’ll only see the output of one command at a time (or a series of commands), but bash is capable of running programs in the background while you’re doing something in the foreground.

Let’s say you kick off a job that’s going to take a long while to run, like gzipping a really large file. If you start that with an & it will tell bash to run it in the background:

gzip really_big_file &

If you forget to add the & or it turns out that a program is taking much longer to run than you expected, you can stop it by using Ctrl-z. This will stop the job and return the bash prompt.

The job can stay stopped indefinitely. Or, you can start it up again and run it in the background by using the bg command. Bash will happily run several jobs in the background or let them stay stopped.

If you want to test the difference between stopped and background, start a GUI application from the shell like Gedit or Firefox, without appending the & and then run Ctrl-z at the shell. You’ll see that the program stops responding, because it’s been stopped. Now, run bg and it will start running in the background and you can interact with it again.

You can bring a job back into the foreground by running fg (foreground). For CLI apps and utilities, this means that their output will go to the console or terminal emulator and they’ll take input from the keyboard again. Note that some jobs don’t handle being run in the background very well, such as top. Then again, there’s really no reason to run top in the background anyway.

Bash is nice enough that it doesn’t let you exit the shell if you’ve left jobs running in the background. If you run exit while a job is in the background, bash will say “There are stopped jobs.” and refuse to exit. The first time, anyway. If you run exit a second time without stopping the job, then bash will exit.

If you want to see all the jobs being handled by bash just run “jobs” at the shell. You’ll see something like this:

[1]+  Stopped                 top [2]   Running                 xload & [3]-  Running                 xclock & 

To work with those jobs using bg or fg, specify the job number. So, to bring xload into the foreground, run:

fg 2 

History

Bash remembers what you do. When you run a command, it’s added to your history. Much like your Web browser history, but even more useful.

Let’s say you run a command with a couple of options or arguments, like so:

sudo zypper se bash

If you want to re-run that command you can scroll up in the history and re-run it, or just type ! to run the last command.

Another handy trick is to use !command to run the last instance of a specific command. So if you’ve been working at the shell for a bit and decide you want to quickly re-run a command that you used earlier, you can use !command and the shell will look through the history and run the last instance of that command with all the options. Let’s say you run the following commands:

ls top cd ~/bin vi command.sh ls 

If you then run !vi it will automatically interpret that as “vi command.sh” without needing to type the entire command. Note that the shell substitutes ~ for your home directory.

You can also see your recent history by typing (big surprise here) “history” at the shell. It will give a numbered list of your commands. You can then re-run commands using !n, where n is the number of the command you want to run again.

Scratching the Surface

I hope that this helps get you started on the shell. There’s a lot to cover when it comes to using the command line, and this only scratches the surface. However, you can find quite a lot of useful info in the Bash Manual in the meantime.