Physics 210 Linux Labs 2, 3 & 4

Contents

LAB2 LAB3 LAB 4

See also

LAB 2

Note:

As we work through these notes you will be typing various commands to the shell. You can expect the output that you see at times to vary somewhat from that in the notes (i.e. some of the output depends on which user executes the command, when it was executed etc.) However, you should always see output that is at least close/similar to that recorded below. In particular, if you mistype something you can expect to receive an error message---for example, if I mistype 'ls' I will see

% lls
bash: lls: command not found
Above all, ask for help from myself or the TAs if something doesn't appear to be working as advertised!

The /phys210 directory and your subdirectory within it

Login and, using a terminal window, locate your personal directory within the /phys210 directory
% cd /phys210/your-login-name
or
% cd /phys210/$LOGNAME
The latter command will work for everyone.

Note:

In the following, whenever you see something that you are to type that includes $LOGNAME, you can replace $LOGNAME with your login (account) name. The instructor will be doing this demo as user phys210d.

% pwd
/phys210/phys210d
Generate a long listing of the directory
% ls -l
total 20
drwx------ 2 phys210d ugrad 4096 Aug 29 12:09 hw1/
drwx------ 2 phys210d ugrad 4096 Aug 29  2012 hw2/
drwx------ 2 phys210d ugrad 4096 Aug 29  2012 hw3/
drwxr-xr-x 2 phys210d ugrad 4096 Nov  8  2012 public_html/
(The output you see will be somewhat different).

Permissions on hw1, hw2 and hw3 have been set so that there can be NO access except by user (i.e. you).

Please keep them that way. (We will discuss permissions in detail in a future lecture/lab).

Change to the public_html directory, When you type pwd following execution of the cd command, you should see /phys210/$LOGNAME/public_html

% cd public_html
% pwd
/phys210/phys210d/public_html

Get a directory listing: it should be a single file index.html.

% ls
index.html
View the contents of the file: in your case you should see the text $LOGNAME
% more index.html
phys210d
We will modify index.html with the web authoring component of Seamonkey shortly, and you will create an entirely new version of it for Problem 2 of Homework 1.

Access /phys210/$LOGNAME/public_html/index.html using a browser as follows.

Point the browser to

http://laplace.physics.ubc.ca/Students/$LOGNAME
e.g., in my case
http://laplace.physics.ubc.ca/Students/phys210d
TYPING $LOGNAME LITERALLY IN THE URL TYPE-IN WILL NOT WORK!!

Again, you should see the name of your account in the browser window.

Two easy pieces

Using kate from the command line

Let's use kate invoked from the command-line to create and edit a file called myname in your homework directory (NOT your home directory).

Type the following commands in a terminal window, and think about what each command is supposed to do as you type it (again, note that you can type your account name rather than $LOGNAME):

% cd /phys210/$LOGNAME
% kate myname

Type your name into the new file, save the file, then exit the kate session. Then type

% ls
and verify that you see myname in the listing. Then execute
% cat myname
What happens?

Using Composer to create/edit web pages

Let's now use the Composer component of Seamonkey to edit the index.html file that lives within the public_html subdirectory (subfolder) of your homework directory, as we saw above.

Instructions:

Collectively exclaim: Oooh ... aahhh!!

ASK FOR HELP AS NECESSARY!!

Control characters

This subject is discussed in a bit of detail in the course notes.

Here, I'll demonstrate how two of the more commonly used control characters work:

Installing the default 210 bash startup files

In a terminal window, change to your home directory:

% cd
Look for the following files
.bash_profile
.bash_login
.profile
.bashrc
.aliases
using
% ls .bash_profile
% ls .bash_login
% ls .profile
% ls .bashrc
% ls .aliases
Be careful to type these and all other commands carefully/correctly, ensuring, in particular, that the names of all files are spelled correctly.

For most of you, every one of the above commands that you type will result in an error message such as:

ls: cannot access .bash_profile: No such file or directory

If any of the files do exist, and unless you're a Linux expert and you know what these files do, and you're happy with their contents, then make backup copies of them as follows, and as necessary, using one or more of the following cp commands:

% cp -i .bash_profile .bash_profile.O
% cp -i .bash_login .bash_login.O
% cp -i .profile .profile.O
% cp -i .bashrc .bashrc.O
% cp -i .aliases .aliases.O
In the highly unlikely case that any of the .O files already exist, then back them up using, for example
% mv -i .bashrc.O .bashrc.OO, 
and re-execute
% cp -i .bashrc .bashrc.O
Now we will copy the PHYS 210 default startup files from the phys210 account to your home directory.

Don't confuse phys210's home, referred to as ~phys210 or /home/phys210 with the /phys210 directory discussed above and in which you will do your homework!

Again, ensure that your terminal session is positioned in your home directory. When youtype pwd following execution of cd, you should of course see /home2/$LOGNAME.

% cd
% pwd
/home/phys210d

Now, do the copying, AND BE CAUTIOUS; i.e. use the -i option to cp. (If cp prompts you to confirm overwrite then you have NOT mv'ed the original file(s) per the above instructions, so go back HERE and try mv'ing the file(s) again.)

% cp -i ~phys210/.bashrc .
% cp -i ~phys210/.profile .
% cp -i ~phys210/.aliases .

Now start up a new terminal window and display the aliases that are defined

% alias
You should see output like the following ...
alias CP='/bin/cp'
alias LN='/bin/ln'
alias MV='/bin/mv'
alias RM='/bin/rm'
alias a='alias'
alias cd..='cd ..'
alias cp='cp -i'
alias d='ls'
alias df='df -h -x supermount'
alias du='du -h'
alias egrep='egrep --color'
alias fgrep='fgrep --color'
alias grep='grep --color'
alias hi='history'
alias l='ls'
alias la='ls -a'
alias ll='ls -l'
alias ln='ln -i'
alias ls='ls --color=auto -CF'
alias lsd='ls -d */'
alias mc='. /usr/libexec/mc/mc-wrapper.sh'
alias md='mkdir'
alias mv='mv -i'
alias p='cd -'
alias rd='rmdir'
alias rm='rm -i'
alias s='cd ..'
... which includes all of aliases that are defined in the .aliases file, plus some more that are "pre-defined" by the default system setup.

The class-default .bashrc file adds some components to your path.

Type the following to display your path: /home/$LOGNAME/bin should appear in it, as well as '.' (the current directory) which means the shell will always look in the current directory for commands to execute

% echo $PATH
.:/home/phys210d/bin:/home/phys210/bin:/usr/local/bin: ...
An alternative way to display the value of the PATH environment variable
% printenv PATH
.:/home/phys210d/bin:/home/phys210/bin:/usr/local/bin: ...

Defining aliases

Let's add a new alias to your ~/.aliases file.

It's a bit inconvenient to have to type

% cd /phys210/$LOGNAME/hw1
to change to your Homework 1 directory, so let's define an alias that will do the job with less typing.

First, cd to your home directory, and make a back up copy of your ~/.aliases file (making back ups before you start modifying important files is an extremely good habit to develop!)

% cd
% cp .aliases .aliases.O
And verify that you now do have a backup, as well as the original
% ls .aliases .aliases.O
.aliases  .aliases.O
Note:

If you haven't done so yet, this is a good chance to start using TAB for filename completion; adopting the practice will ultimately save a lot of typing and reduce the number of typing errors.

Now, continuing to use the command-line, open ~/.aliases with kate:

% cd
% kate .aliases
(if you're resisting using the command-line approach, and attempt to start the editing session either from the file browser [dolphin] or kate itself, note that you will need to enable the display of hidden files, including ~/.aliases, by typing Alt-. (Alt-period).

Then, add the following four lines to the end of the file:

#-----------------------------------------------------------------------
# Define an alias to cd to Homework 1 directory
#-----------------------------------------------------------------------
alias cdhw1="cd /phys210/$LOGNAME/hw1"
Once you have (carefully!) entered these 4 lines, save the file. Note that due to the use of double quotes in the alias definition (we'll discuss this in a future lecture, and see some examples in a later lab), you can use either $LOGNAME literally, or use your actual login (account) name.

Now source ~/.aliases to "activate" the new alias ...

% source ~/.aliases
... verify that 'cdhw1' *has* been defined as an alias ...
% alias cdhw1
alias cdhw1='cd /phys210/phys210d/hw1'
... and try it out
% cdhw1
% pwd
/phys210/phys210d/hw1
If your new alias doesn't work, try to debug what you've done using the above instructions, and/or ask for help!

Exercise: defining aliases

Add additional alias definitions to ~/.aliases to change to your 2nd and 3rd homework directories, as well as to cd to
/phys210/$LOGNAME/public_html

I leave it to you to come up with names for the 3 new aliases.

IMPORTANT!!

Don't forget to make a back up of ~/.aliases BEFORE you start modifying it. This may mean overwriting the old back up, but if everything so far has worked as advertised, that should be OK.

When you're done, be sure to source ~/.aliases, or start a new terminal window, and check that your new definitions have been made and work.

End exercise

ssh

Open a terminal window and type the following
% ssh $LOGNAME@hyper.phas.ubc.ca
where you can either use $LOGNAME literally, or replace it with your account name.

If you have never connected to hyper via ssh (most of you won't have), you should see something like the following:

Warning: Permanently added 'hyper.phas.ubc.ca,142.103.236.100' (RSA) to the list of known hosts.

phys210d@hyper.phas.ubc.ca's password:
Enter the same password that you use to login to the lab machines.

Provided you input the correct password you should be presented with a shell prompt on hyper:

Last login: Wed Jun  4 13:31:19 2014 from bh0.physics.ubc.ca
[phys210d@hyper ~]$

Execute the following command to verify that you are indeed logged into hyper:

% hostname
hyper
Once you have done this, type
% exit
This will close the connection to hyper, and control will be returned to your shell on your lab machine

On hyper, you have the same home directory as on the lab machines, and have access to all of the files therein, as well as /phys210/$LOGNAME and all of the files there as well.

As discussed in the class notes, ssh-ing to hyper will be most useful should you want to connect from from one of your personal machines using PuTty or some other ssh-client if you are running Windows, or from a terminal window if you are using Mac OS or Linux.

Also note that if you don't specify the login name in a ssh command, it is assumed that you want to login using $LOGNAME. The first usage is necessary should you wish to access an account on a remote machine that does not have the same name as the account from which you are issuing the ssh command. Additionally, if the machine to which you are ssh-ing is the search domain---often the part of the fully qualified host name that follows the host name per se---then you can use the short form of the hostname. Thus, since all of the machines in the Physics and Astronomy department are in the same domain

phas.ubc.ca
you can connect from one of the lab machines to hyper by simply typing
% ssh hyper

Finally, as again discussed in the notes, ssh can be used to execute one or more commands on the remote host, and then return immediately return control to the invoking shell. Try the following

% ssh hyper 'hostname; pwd; date'

phys210d@hyper's password: 

hyper
/home/phys210d
Thu Aug 29 12:21:13 PDT 2013

% 
Note that in the above I've used the short version, hyper, of the remote host name, rather than the fully qualified form hyper.phas.ubc.ca.

Changing your password

As discussed in the Unix notes, you must be logged into the main PHAS server, hyper to change your passwd. If you haven't yet changed your password to something that you can remember and/or would prefer to the default that you were issued when you registered for your account, let's do so now. First, ssh into hyper using your current password:

% ssh hyper

phys210d@hyper's password: 

Last login: Sat Sep  6 19:35:43 2014 from cord.phas.ubc.ca
hyper% 
Now, issue the passwd command (no arguments):
hyper% passwd
You will be prompted for your old password: provided that you enter it correctly (if you don't, the shell will tell you that it's sorry, and you can reexecute) you will then be asked for a new password and, provided that it meets the necessary criteria ... ... your password will be changed. Note that it may take a few minutes for the change to be propagated to the lab workstations.

Homework 1

In principle, at this point you should be able to complete Problems 1 and 2 of Homework 1, although you may have to do a little supplementary study via web resources, including those listed in the course Online Resources page.

End of Unix Lab 2

LAB 3

For your amusement ...

Use man to get information on the xeyes command (the DESCRIPTION section in particular), then fire it up from the command-line.
% man xeyes

% xeyes

Sample solution to last lab's aliases exercise

Shell variables

As the notes discuss, there are two type of variables in bash
  1. Local variables
  2. Environment (global) variables

Local variables

Define a few local variables
% a=100

% b=foo

% c='ls -l'

% d='This is a complete sentence.'
and then display their values - remember to use the $ prefix evaluation mechanism---the echo command takes an arbitrary number of arguments, evaluates them if necessary (as in the case of $ constructs) and then "echos" the values to the terminal
% echo $a
100

% echo $b
foo

% echo $c
ls -l

% echo $d
This is a complete sentence.

% echo $a $b $c $d
100 foo ls -l This is a complete sentence.
We can use the value (contents) of c as a command (ls -l)
% $c
total 104
drwxr-xr-x 2 phys210d public  4096 Aug 29 14:54 Desktop
drwxr-xr-x 3 phys210d public  4096 Aug  1 16:02 Documents
drwxr-xr-x 2 phys210d public  4096 Aug  1 16:02 Downloads
drwxr-xr-x 2 phys210d public  4096 Aug  1 16:02 Music
drwxr-xr-x 2 phys210d public  4096 Aug  1 16:02 Pictures
drwxr-xr-x 2 phys210d public  4096 Aug 16  2012 Public
-rw-r--r-- 1 phys210d public  3433 Sep  3 12:11 README-EXERCISE2
                             .
                             .
                             .
drwx------ 2 phys210d public  4096 Oct  3  2013 maplepgm-soln
drwxr-xr-x 2 phys210d public  4096 Oct  3  2013 maplepgm2
drwxr-xr-x 2 phys210d public 16384 Nov 29  2013 matlab
drwxr-xr-x 2 phys210d public  4096 Sep 17  2013 numbers
drwxr-xr-x 3 phys210d public  4096 Oct  7  2013 octave-work
One particularly interesting/useful local variable, PS1 (P-S-one), defines the bash prompt: again, in these notes I'm pretending that my standard prompt is '%', but in reality it's like yours
phys210d@cord ~]$ 
Display the value of PS1
phys210d@cord ~]$ echo $PS1
[\u@\h \W]$
Unless you're a bash expert, this output will not be intelligible to you. A basic explanation is contained in ~/.bashrc:
#-----------------------------------------------------------------------
# Set the command prompt to include the hostname (\h), the username (\u), 
# and the last component (i.e. the basename) of the current working 
# directory (\W).  See 'man bash' and search for 'PROMPTING' for more 
# information on configuring the prompt.
#
# If you want to restore the lab-default prompt which includes the *full*
# pathname, comment-out or delete the following line.
#-----------------------------------------------------------------------
PS1="[\u@\h \W]$ "
For full details see the appropriate section of the online bash manual HERE. Let's set the prompt to "%"
phys210d@cord ~]$ PS1='% '
%
If you want to get it back to the default, source your ~/.bashrc
% source ~/.bashrc
[phys210d@cord ~]$

Note:

You can safely ignore the error message ...

bash: TMOUT: readonly variable
... that may appear when you execute the source command. There's a problem with one of the system startup files that we have to straighten out.

Environment (global) variables

This type of variable is a little more interesting.

First, you can get a listing of all currently defined environment (hereafter abbreviated "env") variables using the bash env command

% env

LC_PAPER=en_CA.UTF-8
LC_ADDRESS=en_CA.UTF-8
XDG_SESSION_ID=c229
LC_MONETARY=en_CA.UTF-8
HOSTNAME=cord
GPG_AGENT_INFO=/tmp/gpg-WDqNl5/S.gpg-agent:10992:1
TERM=xterm
SHELL=/bin/bash
                         .
                         .
                         .
TMP=/tmp
LOGNAME=phys210d
LC_CTYPE=en_CA.UTF-8
SSH_CONNECTION=142.103.234.164 34375 142.103.243.203 22
LESSOPEN=|/usr/bin/lesspipe.sh %s
META_CLASS=download
XDG_RUNTIME_DIR=/run/user/15008
DISPLAY=localhost:10.0
LC_TIME=en_CA.UTF-8
LC_NAME=en_CA.UTF-8
_=/bin/env
Note that, by convention, env vars have all-upper-case names.

Also note that the listing includes the env vars that we have already mentioned/used in the course, including PATH, HOME, USER and LOGNAME

Display the value of one or more specific env vars in one of two ways:

% echo $HOME
/home/phys210d
% printenv HOME
/home/phys210d
Note how in the first case we use $HOME to retrieve the value stored in HOME, while in the second we simply specify the name of the variable.

printenv can take multiple arguments

% printenv HOME USER LOGNAME
/home/phys210d
phys210d
phys210d
Let's define some new env vars of our own
% FOO='foo'
% export FOO
"export" tells bash that FOO is to be an env var, and we can combine the two commands as follows:
% export BAR='bar'
Display the values of FOO and BAR:
% echo $FOO $BAR
foo bar
% printenv FOO BAR
foo
bar

Note:

The printenv form is preferable, since if we forget to export a var, or mess up the export command, echo will still evaluate the var, but printenv won't find it in the list of environment variables ...

% LOL='lol'
% export lol
... where the wrong variable has been exported.
% echo $FOO $LOL
foo lol
% printenv FOO LOL
foo

Now comes the interesting part. First, take a look at the value of the 'shell level' env var ...

% printenv SHLVL
2
... indicating that this is a "2nd-level" shell (why it's 2nd-level and not 1st is a technical issue that we're not going to delve into.)

Now start up a new bash within the original bash

% bash
%
It's difficult to tell that anything happened. But check the value of SHLVL
% printenv SHLVL
3
so this is a "3rd-level" shell, which makes sense; i.e. the current shell is executing within a shell within a shell.

Now, when we started the new, 3nd-level shell, it inherited all of the env vars (and their values) that were defined in the old shell. So check the values of FOO and BAR ...

% echo $FOO $BAR
foo bar

But the local vars that we defined were NOT inherited, so the following echo command echoes "nothing", i.e. an empty line

% echo $a $b $c $d

%
Return to the old shell ...
% exit
exit
% 
Again, it's hard to tell anything happened except that 'exit' is echoed, and SHLVL is back to 2 ...
% printenv SHLVL
2
Should you want to learn how to write bash scripts and functions (optional self-study) topic, you will become more familiar with the use of both types of shell variables.

Bash pattern matching

Recall that pattern matching allows us to select filenames that match a specified pattern (naturally!).

Let's do our work in a directory that contains a LOT of files (2350 to be exact)

cd ~phys210/words

You can expect the following ls command to take a bit of time! It will also generate so much output that it will overflow the terminal's buffer, and you won't be able to scroll back [using the mouse roller button] to see the first part of the output)

% ls

A                       emanate               polysyllabical
Acrania                 emblazer              pomacentroid
Adamic                  embroiler             ponderant
Adoxaceae               emetomorphine         pooa
Akamnik                 emulant               poppethead
Aladdinize              enarbor               porite
                          .
                          .
                          .
Note how ls lists the files in columns according to the collating sequence A, B, C, .. Z, a, b, c ..., z as discussed in the Linux notes.

Now, let's select various sets of filenames using pattern matching.

Get listings of files whose names:

  1. Begin with z
    % ls z*
    
    zabtie     zenithward   zoa            zoomantist  zygal
    zarabanda  zimentwater  zonoplacental  zoospore    zymologic
    
  2. Have a z in them
    % ls *z*
    
    Aladdinize            epitomize             nonsympathizer      torporize
    automatize            Erethizontidae        Nowroze             tzaritza
    azotate               femalize              ozonoscope          uncriticizing
    bacterize             frizziness            paronymize          unminimized
    bedazzlingly          glycogenize           perfectionizement   unmunicipalized
                                    .
                                    .
                                    .
    disequalize           monzonitic            semihydrobenzoinic  zoomantist
    dizenment             muscularize           skeletonization     zoospore
    electrocauterization  Nazerini              squeezing           zygal
    electrolyzer          nomadize              subzygomatic        zymologic
    emblazer              nonanalyzable         sucivilized
    
  3. End with z
    % ls *z
    
    berkowitz  bruzz  untz
    
  4. Are three characters long
    % ls ???
    
    ask  bat  icy  jib  Ker  neo  nix  old  Ona  Ova  ree  she  vex  zoa
    
  5. Begin and end with a vowel (here I won't include 'y' or 'Y' as vowels):
    % ls [aAeEiIoOuU]*[aAeEiIoOuU] 
    
    Acrania           aelurophobe       evocable         oxyaphia
    Adoxaceae         albumoscope       exflagellate     oxyphile
    Aladdinize        alemana           existence        ozonoscope
                              .
                              .
                              .
    aceanthrene       escarbuncle       overobedience    uranite
    acetylsalicylate  esophago          oversimple       urubu
    acolyte           estivage          overturnable     usucaptable
    addlepate         euryscope         oxane
    
  6. Begin and end with a consonant, note consonant = not a vowel, and the caret/hat (^) reverses the sense of the match set
    % ls [^aAeEiIoOuU]*[^aAeEiIoOuU]
    
    Baldwin                 gastrohysterectomy   psorospermial
    Baltis                  gastrular            psycholepsy
    Bandhor                 gelatin              psychosurgery
                      .
                      .
                      .
    gallowglass             pseudocultivated     zoomantist
    gamont                  pseudoholoptic       zygal
    ganner                  pseudonarcotic       zymologic
    garrulously             pseudoracemism
    
  7. Begin with an a, end with a y, and have 6 characters
    % ls a????y
    
    archly  assify  autecy
    

Pattern matching exercise 1

Now devise and execute some of your own pattern matches using the files in ~phys210/words.

Try to be creative, and be prepared to show me or one of the TAs your handiwork.

End exercise

Bash pattern matching can be used in conjunction with any command. For example, let's create a temporary directory, and copy all of the files that have the character sequence 'and' in their names to that directory

Execute the following---again, be very careful with your typing and note that you can type your actual login name rather than $LOGNAME should you wish:

% mkdir -p /tmp/$LOGNAME/mywords
% cp *and* /tmp/$LOGNAME/mywords
The first command creates the new directory /tmp/$LOGNAME/mywords (note the use of the -p option to mkdir to ensure that /tmp/$LOGNAME first gets created if it doesn't already exist), the second does the copying.

Provided that you have issued these commands correctly, you can cd to the temporary directory, and verify that the copying succeeded, as follows

% cd /tmp/$LOGNAME/mywords
% ls

Bandhor      androgenesis  handclap          ribbandry        toyland
Bulanda      cropland      heterandry        sandless         triandrian
Candlemas    distilland    landdrost         sleeveband       wanderluster
Jutlandish   expand        misunderstanding  stylomandibular  zarabanda
Maorilander  grandisonant  northland         substandard
Note that *and* will expand to many words (filenames) so that the last argument to the cp command must be a directory: it it weren't, as in the following, we would get an error message.

Return to the original words directory ...

% cd ~phys210/words
... and issue a faulty 'cp' command ...
% cp *and* /tmp/$LOGNAME/words not-a-dir
cp: target 'not-a-dir' is not a directory

Pattern matching exercise 2

Create a subdirectory morewords within /tmp/$LOGNAME/mywords and copy all files with names beginning with a vowel and ending with 'ing' to that directory. Ask for assistance as necessary.

End exercise

History/ Events

The key thing to remember here is that you can type "history" to see a numbered list of previously typed commands
% history
should generate quite a lot of output for you by this time, and we'll use that fact to advantage in our work with pipes below.

Standard input & standard output

As discussed in the Unix/Linux notes, for many commands Both stdin and stdout are normally "tied" to the terminal, as can be illustrated by executing the cat command with no arguments: since cat reads lines from stdin and writes them to stdout, the net effect is that the command "echoes" every line you type until you terminate the command using ^D (Control-D) or ^C (Control-C)
% cat
isn't
isn't
this
this
fun
fun
?
?
^D
Note that I/you only typed four of the lines in the above. Much of the power and utility of the Unix/Linux command line derives from the stdin/stdout concept, plus the mechanisms of stdin/stdout redirection and piping (connecting stdout of one command to stdin of another).

Output redirection & output append redirection

This is an important topic, so let's work through a few examples of the two types of output redirection

Output redirection

Go to your home directory, and make a directory called redirect, change to it and verify that you're there
% cd
% mkdir redirect
% cd redirect
% pwd
/home/phys210d/redirect
Now copy all of the (non-hidden) files from ~phys210/redirect to the current directory (i.e. ~/redirect), and get a listing to see what was copied. Note that the second argument to the cp command is '.' (dot/period). Again, this is shell shorthand for the current directory
% cp ~phys210/redirect/* .
% ls
fireice  night  pools  road  snowy
The contents of these files are all relatively short poems by Robert Frost.

Look at snowy, for example, using the more command as necessary.

Note:

To control more, type

However, so long as all of the file will fit on the terminal window, such control will not be needed (i.e. there will be no 'paging' of the output).
% more snowy

Whose woods these are I think I know.
His house is in the village, though;
              .
              .
              .
The woods are lovely, dark and deep,
But I have promises to keep,
And miles to go before I sleep,
And miles to go before I sleep.

Now generate a long listing of the directory, but redirect the output of the ls command to a file ls-output
% ls -l > ls-output
Check the contents of ls-output, using cat (for short files, cat and more are essentially equivalent)
% cat ls-output

total 20
-rw-r--r-- 1 phys210d public   0 Sep  6 22:35 ls-output
-rw-r--r-- 1 phys210d public 250 Sep  6 22:35 fireice
-rw-r--r-- 1 phys210d public 614 Sep  6 22:35 night
-rw-r--r-- 1 phys210d public 539 Sep  6 22:35 pools
-rw-r--r-- 1 phys210d public 752 Sep  6 22:35 road
-rw-r--r-- 1 phys210d public 555 Sep  6 22:35 snowy
Note how ls-output appears in the listing, but has 0 size at the time the listing is generated---i.e. bash creates (or overwrites if noclobber is not set) the file to which output is redirected before it executes the command that generates the output

Output append redirection

Assemble the poems into a single file using cat and the output append redirection operator >> (no intervening whitespace between the two <'s)
% cat fireice >> poems
% cat night >> poems
% cat pools >> poems
% cat road >> poems
% cat snowy >> poems
View the collection of poems:
% more poems

Some say the world will end in fire,
Some say in ice.
From what I've tasted of desire
I hold with those who favor fire.
          .
          .
          .
The woods are lovely, dark and deep,
But I have promises to keep,
And miles to go before I sleep,
And miles to go before I sleep.

The above example is a bit contrived as the same end could be achieved as follows (note that we first remove poems, and recall that RM is an alias for the bare-bones Unix rm command that doesn't ask for explicit confirmation before removing the file, [forever!!])
% RM poems
% cat fireice night pools road snowy > poems
% more poems

Some say the world will end in fire,
Some say in ice.
From what I've tasted of desire
I hold with those who favor fire.
          .
          .
          .
The woods are lovely, dark and deep,
But I have promises to keep,
And miles to go before I sleep,
And miles to go before I sleep.

End of Unix Lab 3: Work on HW 1 or vacate the premises as you wish ...

LAB 4

kate (gedit) & .bashrc exercise

You may have noticed that our work at the command line often involves cd commands that are immediately followed by pwd: i.e. we change working directories, then execute pwd to ensure that the new working directory is indeed where we want to be.

I have also pointed out that the default bash prompt includes the trailing component of the full pathname of the working directory; e.g. execute the following (where I am now using the real prompt for user phys210d). Observe that the first cd command ensures that we start from our home directory ...

[phys210d@cord ~]$ cd 

[phys210d@cord ~]$ cd redirect

[phys210d@cord redirect]$ pwd

/home/phys210d/redirect
... and you should see that the prompt text next to the ] changes from ~ to redirect following the second cd command.

To eliminate the need to type pwd after most/all cd's, we can change the prompt variable, PS1 so that it displays the full, rather than truncated, pathname. You may find this useful, at least until you get more familiar with command line work.

The change is simple: we need to modify the line in ~/.bashrc that reads ...

PS1="[\u@\h \W]$ "
... to ...
PS1="[\u@\h \w]$ "
i.e. we only need to change the \W (upper-case W) to \w (lower-case).

Exercise per se

  1. First, in a terminal window change to your home directory and make a backup copy of ~/.bashrc:
    % cd
    % cp .bashrc .bashrc.O
    
    If you are prompted to confirm overwrite ...
    cp: overwrite '.bashrc.O'? 
    
    ... answer y

  2. Now, from within the same terminal window, edit ~/.bashrc with kate or gedit ...
    % kate .bashrc
    
    ... or ...
    % gedit .bashrc
    

  3. Make the change to the setting of PS1, and save the file.

  4. Caution! Do not exit the editor or the terminal window in which you started the editor yet!

  5. Open a new terminal window, and test that the desired change has taken effect, e.g. ...
    [phys210d@cord ~]$ cd /phys210/$LOGNAME/public_html
    
    [phys210d@cord /phys210/phys210d/public_html]$ 
    
    ... or provided that you completed the defining aliases exercise ...
    [phys210d@cord ~]$ cdweb
    
    [phys210d@cord /phys210/phys210d/public_html]$
    
    ... where cdweb in the above is the alias that I defined to change to my web directory; the name of your corresponding alias will probably be different (again assuming that you did complete the exercise.

    Note that the prompt is, of course, considerably longer than it was previously when the working directory is, e.g., your web directory.

  6. Once you are sure that you have made the change correctly, it is safe to exit the editor and, should you choose, exit the terminal window from which you were editing.

  7. If the change was not successful, return to step 3 and try again, asking for assistance as necessary.

  8. Again, the reason that we don't want to exit the original terminal window until we are sure that the changes to ~/.bashrc are correct is that there's the distinct possibility that incorrect changes could cripple our ability to start a new shell. In that case, and assuming that you can't debug the ~/.bashrc, you can always revert to the backup via ...
    % cd
    % cp ~/.bashrc.O ~/.bashrc
    
    ... and where you will have to confirm the overwrite. It's best to be doubly cautious and open a new terminal once you've restored the original, just to be sure that nothing else went awry. And, as always, ask for help if you run into difficulties.

  9. Finally, if you don't like the change, just revert to the backup as has just been described.

Input redirection & pipes

Change to your home directory, create the directory numbers, change to numbers, and verify that the working directory is correct (of course, if you're happy sticking with the change we just made to the prompt, you won't need to execute the pwd):
% cd 
% mkdir numbers 
% cd numbers 
% pwd 
/home/phys210d/numbers

Copy the file ~phys210/numbers/random100 to the working directory (~/numbers) and view the contents of your copy of random100.

% cp ~phys210/numbers/random100 .
% more random100

15
13
6
2
12
4
6
5
17
8
5
2
18
--More--(12%)   

random100 contains a list of 100 randomly generated numbers each in the range 1 to 20, with one number per line.

Verify that there are indeed 100 numbers (lines) in the file by using the wc (word count) command with the -l (list number of lines only) option

% wc -l random100

100 random100

As mentioned briefly in the Unix notes, sort is a powerful command that can be used to (surprise, surprise) sort lines from files or standard input according to various criteria. By default (i.e. if executed with no arguments), sort will

  1. Read lines from standard input until an end-of-file (EOF) is encountered. Recall that you can generate an EOF at the terminal by typing ^D (Control-d)
  2. Sort the lines in alphabetical order, using the collating sequence, A, B, C, ... Y, Z, a, b, z, ..., y, z
  3. Output the sorted lines to standard output

Recall that any command that by default reads and writes to stdin and stdout respectively is known as a filter.

In this exercise we first want to sort the numbers in random100 in ascending numerical order. To do this, we use the -n option (for numeric sort), and redirect the standard input from random100. By default sort outputs to standard output, so we will save the sorted values using output redirection. So let's do the sorting twice, the first with the output going to stdout, the second with output going to the file random100-sorted

% sort -n < random100
1
2
2
2
2
.
.
.
19
20
20
20
20
20
Invoked in this fashion, there's too much information to be seen on the terminal screen. This presents an ideal opportunity to use a pipe, in this case connecting the output of the sort command to the input of more (which also reads from standard input if executed without a filename argument)
% sort -n < random100 | more
1
2
2
2
2
2
2
2
3
3
3
3
4
4
4
--More--   
So now let's execute the same sort command, but this time redirect the (standard) output to a file random100-sorted
% sort -n < random100 > random100-sorted
Sure enough, random100-sorted contains the numbers in ascending order as was the case when we executed sort -n < random100 | more
% more random100-sorted
1
2
2
2
2
2
2
2
3
3
3
3
4
4
4
--More--(11%)      

Question

Why does more show the percentage of the random100-sorted file that has been displayed when it fills the screen, but does not show a percentage when 'sort -n < random100 | more' is executed?

End question

There's another Unix/Linux command, uniq, which like sort, is a filter and which collapses any number of consecutive lines in its input which are identical to a single instance of the line. Thus, we can use sort, uniq and a pipe to generate an ordered list of which integers are contained in random100:

% sort -n < random100 | uniq
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

A quick scan indicates that random100 contains at least one instance of each integer between 1 and 20 inclusive, but we can make an even longer pipeline just to make sure!

% sort -n < random100 | uniq | wc -l
20

We can get sort to sort in descending order using the -r option

% sort -n -r < random100 | uniq

20
19
18
17
16
15
14
13
12
11
10
9
8
7
6
5
4
3
2
1

And, finally, note that the output from a pipeline (not just a single command) can be redirected to a file

% sort -n < random100 | uniq | wc -l > nuniq
% cat nuniq

20
Caution!

You can construct pipelines that are as long as you wish, but for each pipeline, there can be

  1. At most one input redirection; i.e. at most one < per pipeline.
  2. At most one output redirection; i.e. at most one > per pipeline.

In terms of the garden hose analogy I made previously, no matter how many hoses I connect together, there is only one place where the water enters, and one where it leaves. In general, the input redirection will be associated with the first command in the pipeline, and the output redirection with the last.

This is an important point that often trips-up novices.

IMPORTANT!

If you haven't yet thought of this, note that in building up pipelines and other similar constructs (sequences that use input/output redirection), you can save a lot of typing by using the history mechanism (up/down arrows) to retrieve then modify previously issued command lines.

grep & regular expressions

As I have already mentioned, constructing non-trivial regular expressions to use in conjunction with grep constitutes a type of programming in its own right. You should thus expect to have to practice and experiment a bit to get the hang of it. The 3rd and 4th problems of the first homework should definitely provide some practice (and possibly some aggravation, so don't be afraid to ask for hints if you're having trouble!!).

Let's first use grep with the file 'poems' that we generated by concatenating the 5 Robert Frost poems in ~/redirect.

Just to ensure that everyone is working with the same file, execute the following

% cd 
% mkdir grep 
% cd grep 
% cp ~phys210/grep/poems .
When you've done this, you should be in the directory ~/grep and should see the following (with phys210d replaced with your login, and a different timestamp) when you generate a long listing for the directory:
% ls -l
-rw-r--r-- 1 phys210d public 2710 Aug 29 12:51 poems
Now let's use grep to display the following:
  1. All lines in poems that contain the word 'the' (case sensitive)
    % grep the poems
    
    Some say the world will end in fire,
    I have been one acquainted with the night.
    I have outwalked the furthest city light.
    I have looked down the saddest city lane.
                 .
                 .
                 .
    Whose woods these are I think I know.
    His house is in the village, though;
    Between the woods and frozen lake
    The darkest evening of the year.
    To ask if there's some mistake.
    The only other sound's the sweep
    
    (Note how the matches are displayed in the terminal in a different color [red in my case]. This is a configurable feature of grep; i.e. you can control what color is used for highlighting. Use 'man grep' for full details.)

    How many lines are there that contain 'the'?

    % grep the poems | wc -l
    
    30
    

    And how many lines are there that contain 'the' (case insensitive), so includes The (and conceivably ThE, thE, etc.)? Here we use the -i option, for 'ignore case'

    % grep -i the poems | wc -l
    
    33
    
  2. All lines in poems that start with 'I ' (so that 'I' is in the first column of the line and is followed by at least one space).

    Here we use the ^ (caret) to "anchor" the search pattern to the beginning of the line, and since the search pattern includes whitespace, we'll need to enclose the regular expression (regexp) in forward quotes. In fact, just to be safe, we'll quote all the regexps in the subsequent examples (this is a good habit to develop)

    % grep '^I ' poems
    
    I hold with those who favor fire.
    I think I know enough of hate
    I have been one acquainted with the night.
    I have walked out in rain-and back in rain.
    I have outwalked the furthest city light.
    I have looked down the saddest city lane.
    I have passed by the watchman on his beat
    I have stood still and stopped the sound of feet
    I have been one acquainted with the night.
    I doubted if I should ever come back.
    I shall be telling this with a sigh
    I took the one less traveled by,
    
    If we forget to anchor the search at the beginning of the line using the ^, the result is different:
    % grep 'I ' poems 
    
    I hold with those who favor fire.
    I think I know enough of hate
    I have been one acquainted with the night.
    I have walked out in rainâand back in rain.
    I have outwalked the furthest city light.
    I have looked down the saddest city lane.
    I have passed by the watchman on his beat
    I have stood still and stopped the sound of feet
    I have been one acquainted with the night. 
    And sorry I could not travel both
    And be one traveller, long I stood
    And looked down one as far as I could
    Oh, I kept the first for another day!
    I doubted if I should ever come back.
    I shall be telling this with a sigh
    I took the one less traveled by,
    Whose woods these are I think I know.
    But I have promises to keep,
    And miles to go before I sleep,
    And miles to go before I sleep. 
    
  3. All lines in poems that start with either 'I' or 'F' (whitespace not required after either letter in this case):
    % grep '^[IF]' poems
    
    From what I've tasted of desire
    I hold with those who favor fire.
    I think I know enough of hate
    Is also great
    I have been one acquainted with the night.
    I have walked out in rain-and back in rain.
    I have outwalked the furthest city light.
    I have looked down the saddest city lane.
    I have passed by the watchman on his beat
    I have stood still and stopped the sound of feet
    I have been one acquainted with the night.
    From snow that melted only yesterday.
    In leaves no step had trodden black.
    I doubted if I should ever come back.
    I shall be telling this with a sigh
    I took the one less traveled by,
    
  4. All lines in poems that start with any upper case letter in the inclusive range T through Z
    % grep '^[T-Z]' poems
    
    To know that for destruction ice
    When far away an interrupted cry
    These pools that, though in forests, still reflect
    The total sky almost without defect,
    Will like the flowers beside them, soon be gone,
    The trees that have it in their pent-up buds
    To darken nature and be summer woods
    To blot out and drink up and sweep away
    These flowery waters and these watery flowers
    Two roads diverged in a yellow wood,
    To where it bent in the undergrowth;
    Then took the other, as just as fair,
    Though as for that the passing there
    Yet knowing how way leads on to way,
    Two roads diverged in a wood, and I
    Whose woods these are I think I know.
    To watch his woods fill up with snow.
    To stop without a farmhouse near
    The darkest evening of the year.
    To ask if there's some mistake.
    The only other sound's the sweep
    The woods are lovely, dark and deep,
    
  5. All lines in poems that do not start with an upper case letter or a space.

    This one is a bit tricky since we use ^ for two distinct purposes, one to anchor the search to the beginning of the line, the other to negate the sense of the range A-Z plus space, i.e. [^A-Z ] means 'not in the inclusive range A through Z nor a space.

    % grep '^[^A-Z ]' poems
    
    ... and there's no output, so true to form for this type of poetry, the first word of each line is capitalized (assuming every non-blank line starts in the first column).
  6. All lines in poems that contain only one or more spaces.

    This one is also a bit tricky. To ensure that there is at least one space the regular expression needs to have an explicit space. We then follow that with a single character range [ ] that can occur zero or more times, i.e. [ ]*. Finally, we need to anchor the search to both the beginning of the line using ^ and the end of the line using $. Also note that I deliberately added spaces to empty lines in ~phys210/grep/poems to make this example generate some matches.

    % grep '^ [ ]*$' poems
    

    You should "see" many blank lines on the screen at this point. How many? Again, pipe the output into wc -l

    % grep '^ [ ]*$' poems | wc -l
    
    24
    

    Two more examples that may help you with the homework ...

  7. All lines in poems that contain both 'and' and 'the' (case insensitive). We can do this easily by piping two greps together
    % grep -i 'and' poems | grep -i 'the' 
    
    I have stood still and stopped the sound of feet
    And further still at an unearthly height
    And like the flowers beside them, chill and shiver,
    These flowery waters and these watery flowers
    And having perhaps the better claim,
    And that has made all the difference.
    Between the woods and frozen lake
    The woods are lovely, dark and deep,
    

    Note carefully that the first grep in the pipeline is supplied with poems as a file argument, but that the second grep is reading from the standard output of the first one, and hence does not need, and should not be given, a file argument

  8. All lines in poems that are exactly 30 characters long.

    Here you need to be careful to type precisely 30 periods (.) between the ^ and $ that match the beginning and end of a line, respectively. Recall that '.' matches any single character

    % grep '^..............................$' poems
    
    But if it had to perish twice,
    Somewhere ages and ages hence:
    

grep exercise

Repeat the above grep command, but omit the caret (^) and dollar sign ($).

Again, note that it is not necessary to type 30 periods again: just recall and edit the previous command using the arrow keys as usual.

Try to predict what will happen, i.e. how you would state in words which lines will match, before you execute the command.

How many lines match this time?

End exercise

Now let's use grep to look for things in our history and list of environment vars. Here, grep will be used in "filter mode", since history or env will supply the input to grep via a pipe. The output, will, of course, be user-dependent

  1. Look in the history for commands that include the text grep itself.
    % history | grep grep
                     .
    
                     .
                     .
     1132  mv grep numbers redirect words thedate Save
     1227  cd; mkdir grep; cd grep; cp ~phys210/grep/poems .
     1229  grep the poems
     1230  grep the poems | wc -l
     1231  grep -i the poems | wc -l
     1232  grep '^I ' poems
     1233  grep '^[IF]' poems
     1234  grep '^[T-Z]' poems
     1235  grep '^[^A-Z ]' poems
     1236  grep '^ [ ]*$' poems
     1237  grep '^ [ ]*$' poems | wc -l
     1238  grep -i 'and' poems | grep -i 'the'
     1239  grep '^..............................$' poems
     1240  history | grep grep
    

  2. Look in the history for cd commands and only cd commands.

    The regular expression in this case is fairly complex, so take a few moments to study it to try to ensure that you understand what is going on.

    Note the constructions that match:

    1. The command-line numbers, which are all integers, so match "zero or more consecutive digits". Here we take advantage of the fact that every history entry must contain a number, so we don't have to use [0-9][0-9]* rather than [0-9]*.

    2. The spaces before and after the numbers: we require there to be at least one space or semicolon between the number and cd.

    3. At least one space after cd.
    % history | grep '^[ ]*[0-9]*[ ][ ]*cd[ ;]'
    
                        .
                        .
                        .
     1076  cd
     1079  cd; mkdir redirect; cd redirect; pwd
     1092  cd ../grep
     1129  cd ..
     1145  cd
     1185  cd ~phys210/words
     1197  cd; mkdir redirect; cd redirect; pwd
     1213  cd; mkdir numbers; cd numbers; pwd
     1227  cd; mkdir grep; cd grep; cp ~phys210/grep/poems .
    

    Question

    Why won't ...
    % history | grep '[ ][ ]*cd[ ][ ]*'
    
    ... extract the cd commands and only the cd commands?

    End question

  3. Look for environment vars whose names begin with 'LC'
    % env | grep '^LC'
    
    LC_PAPER=en_CA.UTF-8
    LC_ADDRESS=en_CA.UTF-8
    LC_MONETARY=en_CA.UTF-8
    LC_SOURCED=1
    LC_NUMERIC=en_CA.UTF-8
    LC_ALL=POSIX
    LC_TELEPHONE=en_CA.UTF-8
    LC_MESSAGES=en_CA.UTF-8
    LC_COLLATE=en_CA.UTF-8
    LC_IDENTIFICATION=en_CA.UTF-8
    LC_MEASUREMENT=en_CA.UTF-8
    LC_CTYPE=en_CA.UTF-8
    LC_TIME=en_CA.UTF-8
    LC_NAME=en_CA.UTF-8
    

  4. Look for environment vars or values that contain $LOGNAME. Note the in this example the shell evaluates $LOGNAME to your literal account name before executing the grep command:
    % env | grep $LOGNAME
    
    USER=phys210d
    SCREENDIR=/home/phys210d/tmp
    MAIL=/var/spool/mail/phys210d
    PATH=.:/home/phys210d/bin:/home/phys210/bin:/usr/local/bin:/usr/bin:/usr/games:/usr/lib64/qt4/bin
    PWD=/home/phys210d/grep
    HOME=/home/phys210d
    LOGNAME=phys210d
    OLDPWD=/home/phys210d
    

We won't do any more grep lab exercises since you'll get lots of grep practice completing Homework 1!

sed: a stream editor

The Unix sed command provides us with another good platform with which to practice and hone our pattern-matching and pipeline construction skills. sed is a stream editor, meaning that it is designed to read text input from some source, filter and transform the text, and then output it to some destination. sed is a very powerful command and, should you be interested, you can refer to its man page or online information for further details on its use.

Hint: sed may be useful in completing Homework 1

sed is one of the many Unix commands that has a large number of its own subcommands. Here we will illustrate only one of these, namely the substitute command. We will also use sed purely in filter mode, so that it gets its input from standard input, and puts its output to standard output. This is sed's default mode of operation, and, as with all filters, we can use input redirection to make the command get its input from some file, and output redirection to have it put its output in some other file.

Our basic usage of the sed substitution command will be ...

s/regexp/replacement/g
... where regexp is a regular expression (pattern, denoted regular_expression in the Unix notes ) that sed is to look for in the input, and replacement is the replacement text. The leading s, which is short for substitute, is the sed command per se, and the trailing g, short for global, instructs sed to replace all occurrences of regexp that it finds. sed works line by line: if we omit the trailing g then only the first instance of regexp in each line will be replaced.

The slashes in the command are delimiters---i.e. they separate the regexp and replacement---and are used by convention. Provided neither regexp nor replacement contains one or more slashes they are a good choice: if one of more slashes do do appear then use some other character which does not, e.g.

s?regexp?replacement?g

The substitute incantation is a subcommand of the command sed. To have sed perform the subcommand we pass it to sed on the command-line as follows:

% sed 's/regexp/replacement/g'
We enclose the subcommand in single quotes to inhibit any interpretation of special characters in regexp or replacement by the shell. As is the case when passing patterns to the grep command, it is good practice to always do this, even if isn't strictly necessary.

Let's now consider a few examples. In your terminal window change to the redirect subdirectory of your home, and get a listing of its contents:

% cd ~/redirect
% ls
fireice  ls-output  night  poems  pools  road  snowy
Using grep, verify that there are two lines in fireice that contain the word (or pattern) fire ...
% grep 'fire' fireice
Some say the world will end in fire,
I hold with those who favor fire.
... and then transform the contents of fireice so that fire has been replaced by an inferno. Since we are using sed in filter mode, we will use input redirection so that it gets its input from the file fireice. Type the following carefully:
% sed 's/fire/an inferno/g' < fireice
The output should be
Some say the world will end in an inferno,
Some say in ice.
From what I've tasted of desire
I hold with those who favor an inferno.
But if it had to perish twice,
I think I know enough of hate
To know that for destruction ice
Is also great
And would suffice.
Note how the occurrences of fire have been replaced by an inferno. Again, since we are using sed in filter-mode, the output appears on the terminal (standard output). We can redirect the output to a file, say inferno-ice, as follows:
% sed 's/fire/an inferno/g' < fireice > inferno-ice
Verify that the contents of inferno-ice are precisely what we saw in the first invocation of sed where the output appeared directly on the terminal ...
% cat inferno-ice

Some say the world will end in an inferno,
Some say in ice.
From what I've tasted of desire
I hold with those who favor an inferno.
But if it had to perish twice,
I think I know enough of hate
To know that for destruction ice
Is also great
And would suffice.
Now, you might think that we could use sed to replace all occurrences of fire in poems with an inferno---i.e. to modify the contents of poems in place---via
% sed 's/fire/an inferno/g' < fireice > fireice
However, this will not do what we want---instead the shell will complain ...
-bash: fireice: cannot overwrite existing file
... since as we've observed previously, as soon as the shell detects output redirection to a file, it wants to create that file anew. Since we have the noclobber shell option set, bash won't let us do that. In the sed exercise below you will have a chance to demonstrate your command-line/sed prowess by figuring out how to accomplish the in-file replacements.

Now let's use sed twice via a pipeline to change all occurrences of fire to an inferno and all instances of ice to frigidity by executing ...

% sed 's/fire/an inferno/g' < fireice | sed 's/ice/frigidity/g'
... which generates ...
Some say the world will end in an inferno,
Some say in frigidity.
From what I've tasted of desire
I hold with those who favor an inferno.
But if it had to perish twfrigidity,
I think I know enough of hate
To know that for destruction frigidity
Is also great
And would sufffrigidity.

... which is not quite what we wanted (presumably). I'll leave the debugging to you as an exercise.

Here's one last example (potentially useful for the first homework, hint, hint, nudge, nudge, wink, wink, ...) which, in contrast to the two above, uses a non-trivial regular expression as the search pattern. Let's use sed to filter all lines of the file poems so that only the first word of each line remains. An appropriate command is:

sed 's/ .*$//g' < poems
The regular expression in the above will match a space character followed by any string of characters to the end of the line, and sed will then replace that with literally nothing (i.e. there is no string, or a null string, between the final two delimiters). In effect, and assuming that every line begins with a non-space character in the first column, this deletes all of the text following the first word in each line.

The output is

Some
Some
From
I
But
I
To
Is
And

I
I
I
 .
 .
 .
The
But
And
And
Again, this perhaps isn't quite what we want since the output contains lines that contain no word, but rather only spaces or perhaps "nothing" (i.e. no characters before the new line). But we can easily get rid of those lines by piping the above command into a grep command ...
sed 's/ .*$//g' < poems | grep -v '^[ ]*$'

Some
Some
From
I
But
I
To
Is
And
I
I
I
 .
 .
 .
The
But
And
And
... and, sure enough, the "empty" lines are gone.

sed exercise

Working in your ~/redirect directory, make a copy of fireice named myfireice. Construct a sequence of commands---i.e. you can use more than one command/pipeline---that replaces all occurrences of say in that new file with state. I.e. after your command sequence has been executed the contents of myfireice should contain state's wherever there were previously say's.

End exercise

Optional pipeline exercise

Try to do this if you have some time while waiting for the class to finish up with the sed exercise:

Add stages to the pipeline ...

sed 's/ .*$//g' < poems | grep -v '^[ ]*$'
... so that the new pipeline produces the number of distinct words that start the lines in poems.

End exercise

All those quotes

We'll keep this section brief since the various quoting mechanisms available, and the distinctions among them, are most relevant in the context of shell programming, which we will not be studying at this time. Thus, we'll simply work through the examples from the notes.

That said, be sure you understand how the backquotes operate since they may be very useful in completing what some of you may find a particularly challenging problem in Homework 1 (hint, hint!)

Forward quotes

Recall that these quotes inhibit shell evaluation of any and all special characters and/or constructs, as we have already seen in some of the grep examples:

% a=100
% echo $a
100

% b=$a
% echo $b
100

% b='$a'
% echo $b
$a

Note how the forward quotes stop the shell from replacing $a with its value prior to the assignment to b.

Double quotes

Recall that these work like single quotes, except that the shell "looks inside" them and evaluates

  1. any references to the values of shell variables
  2. anything within backquotes (see below)
% a=100
% echo $a
100

% string="The value of a is $a"
% echo $string
The value of a is 100

You should now understand how/why if you defined the alias cdhw1 using

% alias cdhw1="cd /phys210/$LOGNAME/hw1"
that you see $LOGNAME replaced by your login name when you subsequently ask to see the definition of cdhw1.
% alias cdhw1
alias cdhw1='cd /phys210/phys210d/hw1'

(If you used your actual account name rather than $LOGNAME in the definition of cdhw1, cdhw2, etc., you might want to try modifying the definitions to use $LOGNAME).

Backward quotes (backquotes, backticks)

Recall that these quotes (backticks) provide the useful and very powerful mechanism that allows you to capture the output from a command (or, in general, a pipeline) as a string, which can then, for example, be assigned to a shell variable, or supplied as an argument to another command:

% date
Thu Aug 29 12:57:18 PDT 2013

% thedate=`date`
% echo $thedate
Thu Aug 29 12:57:29 PDT 2013

% which true
/usr/bin/true

% file `which true`
/usr/bin/true: ELF 64-bit LSB executable, x86-64 ...

% file `which true` `which false`
/usr/bin/true:  ELF 64-bit LSB executable, x86-64 ..
/usr/bin/false: ELF 64-bit LSB executable, x86-64 ...
As mentioned in the Unix/Linux notes, the file command attempts to determine what type of contents its arguments (which should be files) contain and which reports full pathnames for commands that are supplied as arguments. Observe that in the last example, multiple backquoting constructs are used on a single command line.

Backquotes exercise

Part a)

Use backquotes to compose a single command that stores the names of the files in the working directory in the shell variable mylist. For example, when you execute ...
% cd ~phys210t
% your-command-here
% echo $mylist
... you should see output such as the following ...
cmd dir1/ dir2/
Hint (?): The entire command can be as few as 11 characters in length.

Part b) -- trickier

The output from echo $mylist in the above includes the slash character following the names of the directories. If your solution to Part a) displays the same behaviour, modify the command so that the slashes do not appear.

Hint: which ls is the "real" (i.e. non-aliased) ls?

End exercise

A brief introduction to gnuplot

Gnuplot is a plotting package that is popular in the Linux community and which suffices to produce basic plots and graphs of the type that instructors in your other courses are apt to ask you to make on occasion. I will not spend a significant amount of time instructing you on the use of gnuplot, but there is a question on the first homework that requires you to use it to make two plots, one of a specific mathematical function, and the other that displays some datasets read from a file. You are expected to use gnuplot's built in help facility, as well as on-line material to solve the homework problem and, in general, to ensure that you can use gnuplot to do basic plotting tasks. Here I note that some previous students of 210 who have received good marks in the course, including the first homework, have apparently forgotten---on the timescale of a year or less---that they know, at least in principle, how to make such plots! Please don't follow in their footsteps: although I don't expect you to remember all of the gnuplot syntax that you need to do the homework, I do expect you to remember that you did some basic plotting and that you made a record of what you did in a README file!

With that harangue out of the way, let me illustrate just a couple of things that will get you going with gnuplot. Note that the application is command-line driven, has many distinct commands of its own, and that many of those commands (including fundamental ones such as plot) have a syntax that can become quite complicated. That said, it also quite straightforward to make simple plots.

First, start the application from the bash command-line:

% gnuplot

gnuplot>
Observe that
gnuplot>
is the gnuplot prompt which, as you can probably deduce, indicates that gnuplot is waiting for you to type a command.

One of the nice things about gnuplot is that it is easy to plot quantities that are explicit functions of a single variable; i.e. expressions which use the usual arithmetic operations and most standard mathematical functions (sin, cos, tan, log, exp, ...)

Try the following ...

gnuplot> plot sin(x) 
... and you should see the plotting window appear, displaying a basic plot of sin(x) on the domain x = [-10 ... 10].

gnuplot has an extensive built-in help facility, type help for an overview:

gnuplot> help

`Gnuplot` is a portable command-line driven graphing utility for Linux, OS/2,
 MS Windows, OSX, VMS, and many other platforms. The source code is copyrighted
 but freely distributed (i.e., you don't have to pay for it). It was originally
 created to allow scientists and students to visualize mathematical functions
 and data interactively, but has grown to support many non-interactive uses
 such as web scripting. It is also used as a plotting engine by third-party
 applications like Octave. Gnuplot has been supported and under active
 development since 1986.
                                    .
                                    .
                                    .
Press return for more:
At the end of the help overview you will see a list of topics for which you can get detailed help. For example, the plot command is extremely important, and it is worth your time to do a little perusing of the help pages for it.
gnuplot> help plot

 `plot` is the primary command for drawing plots with `gnuplot`.  It creates
 plots of functions and data in many, many ways.  `plot` is used to draw 2D
 functions and data; `splot` draws 2D projections of 3D surfaces and data.
 `plot` and `splot` offer many features in common; see `splot` for differences.
 Note specifically that although the `binary ` variation does
 work for both `plot` and `splot`, there are small differences between them.

 Syntax:
       plot {<ranges>
            {<iteration>
            {<function> | {"<datafile> {datafile-modifiers}}}
            {axes <axes> {<title-spec> {with <style>
            {, {definitions{,}} <function< ...}
                                .
                                .
                                .
Subtopics available for plot:
    acsplines         axes              bezier            binary
    cnormal           csplines          cumulative        data
    datafile          errorbars         errorlines        every
    example           frequency         functions         index
    iteration         kdensity          matrix            parametric
    ranges            sbezier           smooth            special-filenames
    style             thru              title             unique
    using             volatile          with
Subtopic of plot:

You can now type in one of the plot subtopics for help with it, or simply Enter to return to the top level prompt.

It's always good to learn a computational facility through examples, so ask gnuplot for some sample usages of plot

Subtopic of plot: example

 This example plots the data in the file "population.dat" and a theoretical
 curve:

       pop(x) = 103*exp((1965-x)/10)
       set xrange [1960:1990]
       plot 'population.dat', pop(x)
                    .
                    .
                    .

One command in gnuplot that is frequently problematic for newcomers, and that you will need to use in completing the first homework is

set terminal

As you can read in more detail via ...

gnuplot> help set terminal
... gnuplot can display graphics to many devices, and in fact the authors of gnuplot arguably should have adopted the term (keyword) device rather than terminal to minimize confusion with the terminal application per se in which gnuplot is typically executed. But they didn't, so we need to understand what terminal means in this context ...

In the "old days" we tended to use many different physical graphics devices, such as different types of hardcopy plotters and special-purpose graphics displays sold by various and sundry vendors. Click HERE to see an image of a Tektronix 4014 which is a device that I have fond memories of and which at $10,000 or so back in the 70's and 80's---perhaps $30k in today's dollars---was a bargain. Each of these devices effectively spoke its own language, and "high level" plotting programs such as gnuplot had to be able to translate their graphing instructions into those languages. You told a program like gnuplot which specific device you wanted to talk to and it generated the appropriate code to make the device perform the requisite plotting task.

In the current era, although there is still a proliferation of graphics devices (indeed, more so than in the "old days"), we tend to restrict use to the following "terminal types" (think devices, or places that the graphics output is directed):

To use one of the latter devices we not only have to specify the terminal type, but also the name of a file in which the image is to be output. This second step is done with the gnuplot set output command.

Thus, your solutions to the homework problems involving gnuplot will generally incorporate a sequence like ...

gnuplot> set terminal ...
gnuplot> set output ...
... where you will need to figure out what to replace the ellipses (...) with.

Also note that the for any particular terminal type there are a variety of options that can be set to control features such as line types, fonts used, font sizes, etc. Use, e.g.

gnuplot> help set terminal wxt
to see the available options for the default terminal type.

We now consider a feature of gnuplot which illustrates a general principle that is applicable to essentially all interactive computer work that involves typing text:

Whenever possible, type commands into a text file and then input them to the command-line driven program using its facility for reading commands from a file (assuming that one exists).
Such a facility does exists for most self-respecting command-driven systems and I will reemphasize the essential utility of the principle throughout the course.

I will reemphasize the essential utility of the principle throughout the course.

I will reemphasize the essential utility of the principle throughout the course.

You get the point.

To see how this works in gnuplot, do the following:

  1. Terminate your gnuplot session using the command quit (or exit)
  2. Using the bash command-line, create a subdirectory of your home directory named plot, cd to it and restart gnuplot:
    % cd 
    % mkdir plot
    % cd plot
    % gnuplot
    
  3. Open a new terminal window: Ctrl-Shift-N within the existing one will create a new one, or you can use a menu selection: File -> New Window
  4. In that window enter the following commands
    % cd
    % cd plot
    % kate gnuplot-input
    
  5. In the kate window, not at the gnuplot prompt, enter the following text
    plot cos(x)**2
    
    (** is the exponentiation operator in gnuplot) and save the file. Remember that since we started kate from the command-line with the name of a file (a new one in this case), we don't have to tell the editor what to call the file when it is saved. Also, since kate was started in the directory ~/plot, the file will be saved there as well.

    Important terminology:

    In computer science, a file that contains a list of commands for some normally interactively command-line-driven program is generically called a script.

    End terminology

    We will use the term script throughout the course, including in the contexts of Maple and MATLAB programming.

  6. Return to the window running gnuplot and enter the following:
    load 'gnuplot-input'
    
    Ensure that you enclose the name of the file in quotes or gnuplot will emit an error message. Gnuplot doesn't care whether you use single or double quotes, so
    load "gnuplot-input"
    
    is equivalent.

Once you enter the load command, the gnuplot window should pop up with a plot of \(\cos(x^2)\).

After the commands in the script file gnuplot-input have been "loaded" (and executed), control of gnuplot returns to the command-line and you can continue to issue directives interactively. Better still, if you take the script-based approach to heart (and I recommend that you do!) you can:

  1. Modify the script.
  2. Save it.
  3. Reload it into gnuplot (note that you can recall the previous load command using the up-arrow key).
  4. Repeat as necessary until you're satisfied with your plot.
The advantages of using the load mechanism include:
  1. It is easier to edit gnuplot "code" using kate than via the command line.
  2. You automatically maintain a record of what plotting commands you used to perform a particular graphing task, including all of the syntactic idiosyncracies that you had to deal with.
  3. Crucially, the files of commands that you create can serve as templates for subsequent plotting chores. When doing programming of any sort it is easier to start from something that works and then modify than to start from scratch.

I reiterate that these benefits generally apply whenever one is working with a command-line oriented system, including the shell, or, as we shall see later in the course, maple and MATLAB.

I'll conclude this whirlwind introduction by pointing out that one very useful utility command is test

gnuplot> test
As you can see, this produces a display in the plotting window which shows many of the various attributes (linestyles, colors, marker types, ...) that you can use in making/adorning a basic plot.

Note that when you set non-default terminal options via

gnuplot> set terminal which-terminal option1 option2 ...
you should use test to see how the various plotting attributes have changed relative to the default.

gnuplot exercise

Modify the script gnuplot-input so that it plots \(\cos(x^2)\) using a green dashed line, and gives the plot a title

My plot of cos(x**2)
with the title text in blue.

I suggest that you figure out how to plot the title first.

You may find

gnuplot> help set terminal wxt
gnuplot> help plot
gnuplot> help plot style
gnuplot> help title
gnuplot> help colors
and/or appropriate google searches useful.

Hint

You will need to use

gnuplot> set terminal wxt some-option
to plot with dashed lines. Remember to use the
gnuplot> test
command to see the linestyles, colors, etc. that result from the option(s) you supply.

Note

As much as possible, please try to do this exercise by yourself and try to resist telling your classmates how you did it until they have done it as well.

Remember to always save the script file when you have changed it, before you reload it into gnuplot.

Also note that, as is the case when working with all programmable environments, there are many ways to complete the exercise, so don't be surprised if your solution is different from your classmates'.

End exercise

End of Unix Lab 4: Work on HW 1 or head out as you wish ...