CSE 374, Lecture 2: The Shell

So far

So far we've learned about a few basic bash commands:

    pwd, ls, cd, cat, cp, mv, rm, man

We're basically learning how to to use a computer from scratch. Once we learn the model, things will speed up.

Today we'll learn the rest of the model and then talk about text editing.

Getting help

So far we've seen a bunch of simple commands that help us navigate and examine the file system (ls, cd, cat, cp, mv, rm). But now I want to do something more complicated: I want to list not just the contents of the current directory (which I could do with "ls") but also the time at which each file was last modified. This was something easy to see in the GUI world: the Finder showed times next to the name of each file. How will we figure out how to do this?

Linux has a built-in manuals (files containing documentation) that describe the commands and programs that we've been running. We call these "man pages", and we can access them by using the "man" command.

    $ man ls

That command gives us a large amount of information about how the "ls" command works. We can use the up and down keys to view the whole page (or, as the man page directs at the bottom of the screen, press "h" to learn more about how to navigate a man page). The man page lists how to use the ls command: provide the ls command followed by one or more "options" and then the name of a file.

    ls [OPTION]... [FILE]...

What is an option? The man page lists those too. Options are usually represented as one or two dashes followed by one or more characters, and they customize the behavior of the command. For example, in the ls man page we can see that the "-c" command, when used with the "-lt" command, will "sort by, and show, ctime (time of last modification of file status information)". So to achieve our goal of displaying files with modification time, we can run the following command:

    $ ls -c -lt

Options can be combined behind a single dash. The previous command is identical to this one:

    $ ls -ltc

You can use the "man" command to find out information about other commands, too:

    $ man mv
    $ man rm
    $ man pwd

Man pages are viewable online. Check out the Links section of the course webpage to find a link to the online Linux man pages reference. You can explore the documentation to learn about other commands (check out the intro link). You can also use the Linux pocket guide, if you've bought it, to learn about different commands and tools.

Another way to get help and understand how a command works is to use the --help option:

    $ ls --help

Most built-in commands and also most more complicated programs that you run from the command line support the --help option. The output from --help is printed to the terminal, not displayed in the nice format of the man page, but it is another option for you.

What if you forget all the things that we've discussed today? Well the shell will help you out if you just type "help".

    $ help

Special characters

In the ls man page, you may have noticed a couple options that refer to . (one dot) and .. (two dots). What do those mean?

There are some "special characters" that you can use in the shell.

    .   # current directory
    ..  # parent directory
    ~   # home directory for your user

We can use these commands to simplify navigating the file system. To navigate up one level, before we had to give the full path of the parent directory:

    # if we are in /homes/mwinst/foo/baz
    $ cd /homes/mwinst/foo

But now, we can use the .. shortcut to do the same thing:

    $ cd ..  # moves one directory up in the file system

Similarly for the home directory:

    $ cd /homes/mwinst  # old version
    $ cd ~              # using the special tilde character

Shell history, autocomplete

Typing all these commands is a lot of typing! I thought I said that the shell can be a lot faster than a GUI? There are a few ways to make things faster.

If you start typing a file name, you can use the tab key to autocomplete the file name. For example if I start typing this:

    $ less An

and then I hit tab, if there is a file that starts with An in the current directory, it will auto-complete for you.

    $ less AnnaKarenina.txt

You can also use the up arrow to get to previous commands (and the down arrow to get back again).

Similarly, the "history" command will list out all the commands that you've used in the past.

    $ history
        1  cd books
        2  ls AnnaKarenina.txt
        3  history

(what's that "less" command that I just used? use "man" to find out what it does! there's also a "head" and a "tail" command that might help you out!)

Filename metacharacters

How else can we do things faster in the shell? The shell is actually not just a simple program that takes a command and executes it. It can also take that command and perform SUBSTITUTIONS in order to avoid having to type file names directly.

For example, the "*" character is a special character. It means "all files in the current directory". So if I am in a directory that contains two sub-folders bar, and baz, then "ls *" will essentially perform "ls bar baz". It will substitute all files into the command.

    $ ls *
    bar:
    a.txt  b.txt  test2.txt  test.txt

    baz:
    pun.txt

So I lied a bit. "*" actually stands for "zero or more characters". So if you add additionally characters around the star, you can get different results.

    $ ls bar/*
    bar/a.txt bar/b.txt bar/test2.txt bar/test.txt
    $ ls bar/test*
    bar/test2.txt  bar/test.txt

The ? character is also special - it means one and exactly one character, rather than "*" which means "zero or more".

    $ ls bar/tes?.txt
    bar/test.txt

OK, but what if I ACTUALLY want to use the "" character, and I don't want to use it in this "zero or more characters" sense? If you actually want a *, you can surround it with quotes ("", or '*'). This is easy to see with the "echo" command, which echos what you give it as input.

    $ echo *
    bar baz
    $ echo "*"
    *

More special characters

The up arrow isn't the only way to find previous commands and re-execute them. You have a couple of other options too.

To repeat the last command, you can use two exclamation points in a row.

    $ cat test.txt
    This is a test
    $ !!
    cat test.txt
    This is a test

If you want to be a little bit more specific, you can use a single exclamation point plus a string. Then the shell will execute the last command that starts with that string.

    $ cat test.txt
    This is a test
    $ ls
    test.txt
    $ !ca  # This will match "cat test.txt"
    This is a test

If you know some part of the previous command but you don't remember how it started, you can use "!?" to search find and execute the last command that has the string anywhere in the command.

    $ cat test.txt
    This is a test
    $ ls
    test.txt
    $ !?test  # This will match "cat test.txt"
    This is a test

Be careful - if you use these shortcuts, there is no way to undo them! You should be sure about what you're getting before you do this.

Users

A brief detour. We've seen that each computer can have one operating system (Linux), one file system, and one or more CPUs. But it can also have multiple users, as we've seen with klaatu (you all are users).

You can use the command whoami to see your current username:

    $ whoami
    mwinst

To see who else is logged in, you can use the command who. I demonstrated this by logging into two ssh sessions at once.

    $ who
    mwinst   pts/11       2018-03-27 19:53 (97-126-87-104.tukw.qwest.net)

If you want to know more about someone in particular, you can "finger" them. Yes, I know it sounds wrong, but that's the name that it has been given.

    $ finger mwinst
    Login: mwinst                           Name: 
    Directory: /homes/mwinst                Shell: /bin/bash
    Last login Mon Jan 1 10:00 (PDT) on pts/3 from xxxxx

You can even send messages to other users via the "write" command by providing their username and pts value from who.

    $ write mwinst pts/11  # pts/11 is from the who command
    Hello Melissa!

To see all users who are authorized on this system, you can look at the /etc/passwd file:

    $ cat /etc/passwd

This file no longer stores actual passwords (it's not secure enough!) but it does store users along with their shell and the name of their home directory.

Each file in the file system also has the concept of "permissions". Who owns the file? Who is permitted to view it? Who is permitted to edit it? For example, if I try to see the files in your personal directory, I'm going to get an error, because your user owns it and not me:

    $ cd /homes/astudent
    -bash: cd: /homes/astudent/: Permission denied

We can see who owns each file by running the ls command with an extra "-l" option.

    $ ls -l /homes/
    ...
    drwxrw-r--  9 mwinst   4096 Mar 25 16:18 mwinst
    ...

When we do this, we can see that each of you "owns" your own home directory (that's what the first "mwinst" means). We can also see a set of permissions that look like a combination of "drwx" and dashes. What does this mean? Well, the r means "read", w means "write", and x means "execute" (coming soon). And there are permissions for three different categories of people: the owner, the "group" (won't discuss this right now), and everyone. So in the above example, the owner can read, write or execute the file; anyone in the group can read or write the file; and the general population can read the file.

You can change the permissions on a file by using the command "chmod" (which stands for "change mode"). Look at the man page for chmod to learn more. If I want to enable anyone to read the file foo.txt, I can say:

    $ chmod a+r foo.txt

Some users are special. These are "administrators". They can do things and go places that other people can't. For example, they can change the password of any user. You can't do this on klaatu - you are not permitted to change the shared server in this way :) but you are a superuser if you're running your own virtual machine. To run a command as a superuser, use the "sudo" command. For instance, to change your password (if you were user mwinst), you can run:

    $ sudo passwd mwinst

Programs & Processes

When we're in the shell, we also will talk about programs and processes.

A "program" is a file that can be executed. This includes any applications that you are using, including things like text editors or utilities (or the shell itself!). A "process", on the other hand, is the term for running code or a running program - one that is actually currently occurring. Each application may have many processes because it is doing many complicated things at once (more in the Concurrency section). Each process has its own separate "memory" or programmatic data (think arrays, variables, etc).

To see what processes are running on the computer, we can use the ps command:

    $ ps aux  # "aux" tells ps to show every process on the computer

The output of ps can be kind of messy, so you can also use top:

    $ top

We also have a concept of "foreground" and "background" processes. The "foreground" process is the one that you are currently interacting with (for instance, the terminal, or top itself). Normally when you start a process, it is in "foreground" mode, but you can tell it to start up in background mode by appending an ampersand to the command.

    $ top &
    [1] 30492

Note that we don't see the result of top! We just see this number. But then if we type "fg" - which tells the shell to bring that task into the foreground - we see the full top program running as we expected to see.

    $ fg

You can also kill specific processes if you'd like by providing the process number (eg 30492 above, or the number that you see in top or ps). This is very useful if you ever have a misbehaving program and it won't execute normally.

    $ kill 30492

emacs

Now we're at a point where we really need a text editor so we can modify files. We'll be using a tool called "emacs" to do that. You can run emacs on a file:

    $ emacs test.txt

This is a programmable, extensible text editor. What does that mean? It has its own programming language to customize the shortcuts and utilities that are available to you (explore on your own, not covered in this course). That makes it powerful, but also complicated. Emacs comes with a built-in tutorial to get you started: type "ctrl-h t" (with the control character) to enter the tutorial.

Some helpful shortcuts to get you started:

    C-x C-s  # save (ctrl-x, ctrl-s)
    C-x C-c  # quit (ctrl-x, ctrl-c)
    C-e      # go to end of line (ctrl-e)
    C-a      # go to beginning of line (ctrl-a)
    C-x C-f  # enter a file name to view a different file

There is an epic war in the programming community between proponents of emacs and proponents of another text editor called "Vim". I do NOT want to get involved in that war - you are free to use whatever text editor you prefer. However, do note that emacs shortcuts often work in other programs as well - including bash! Once you start getting the hang of the emacs shortcuts, try them in bash to see what happens. These will help to make you more efficient.

Customizing your experience

In your home directory, you can create a file called ".bashrc". This is a file to customize your bash shell. I showed my .bashrc file.

    # .bashrc
    # Source global definitions
    if [ -f /etc/bashrc ]; then
            . /etc/bashrc
    fi

    alias ls='ls -G --color=auto'
    alias grep='grep --color'
    alias rm='rm -i'

    e() {
        emacs ~/.bashrc;
        source ~/.bashrc;
    }

    export PS1='\h:\w$ '
    export EDITOR='emacs'

We talked about the different elements of the file. There is an "if" structure (we'll talk about that later) that loads a "global version" of the bashrc file (some common utilities - check it out yourself!). It then sets some aliases. An alias is a command that bash substitutes with another command. So for example, when we say "alias ls='ls -G --color=auto'", that means that any time I type "ls", it will actually be as if I had typed "ls -G --color=auto". Aliases make commands much shorter!

Your .bashrc file is loaded on startup (when you login via ssh), or whenever the "source" command is run. "source" is a builtin command in bash that says "execute every line as if the user had typed it in directly in the shell". So if you modify your .bashrc file, you will need to run "source" in order for it to actually use your changes:

     $ source .bashrc

Summary