------------------------------------------------------------------------- PHYS210 2009-09-17 LAB SUMMARY scp, shell variables, bash pattern matching, history, standard input and standard output, input/output redirection, pipes, grep and regular expressions, all those quotes (The instructor will be gob-smacked (i.e. amazed) if we get through all of this in one lab!) ------------------------------------------------------------------------- 1) SCP Ensure that you are in your home directory, and create a file called thedate using the date command and output redirection and use cat to view the contents of thedate % cd % date > thedate % cat thedate Wed Sep 16 13:54:22 PDT 2009 Try executing the date > thedate command again (use the up-arrow to retrieve the command) and note how bash stops you from overwriting thedate because the noclobber shell option is on % date > thedate -bash: thedate: cannot overwrite existing file % echo $SHELLOPTS braceexpand:emacs:hashall:histexpand:history:ignoreeof:interactive-comments:monitor:noclobber Now, use scp to copy thedate to your home directory on the main physics server warp.phas.ubc.ca (or physics.ubc.ca). Note that we can refer to the machine simply as warp or physics when logged into hyper, but for completeness, we'll use the long form. As usual, wherever $LOGNAME appears, you can either literally use $LOGNAME or your actual login name Check that you're still in your home directory, and if you're not use cd to get there % pwd /home2/phys210t Copy the file from hyper to warp. Note that you will likely receive a message asking whether you want to continue connecting. Confirm by entering yes (y will NOT suffice) % scp thedate $LOGNAME@warp.phas.ubc.ca:~ The authenticity of host 'warp.phas.ubc.ca (142.103.236.11)' can't be established. RSA key fingerprint is 61:38:d3:bf:0d:9a:da:6e:e1:cf:f4:ca:d6:38:eb:c0. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added 'warp.phas.ubc.ca,142.103.236.11' (RSA) to the list of known hosts. phys210t@warp.phas.ubc.ca's password: Type your password (the same one that you use for hyper), and you should see something like the following thedate 100% 29 0.0KB/s 00:00 Now, using ssh to warp.phas.ubc.ca, confirm that the copy was successful - this time we'll use two shortcuts i) use the short name, warp, for the host ii) omit the $LOGNAME@ part which is the DEFAULT for ssh and scp---i.e. if your login (account) name is the same on both machines, there is no need to supply it to either ssh or scp % ssh warp 'cat thedate' phys210t@warp's password: Wed Sep 16 13:54:22 PDT 2009 ------------------------------------------------------------------------- 2) SHELL VARIABLES Recall that in bash there are two types of variables i) Local variables ii) Environment (global) variables ------------------------------------------------------------------------- 2a) 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 % echo $a 100 % echo $b foo % echo $c ls -l % echo $d This is a complete sentence. We can use the value (contents) of c as a command (ls -l) % $c -rwxr-xr-x 1 phys210t ugrad 53 2009-08-31 20:12 cmd drwxr-xr-x 2 phys210t ugrad 4096 2009-09-15 15:43 Desktop drwxr-xr-x 4 phys210t ugrad 4096 2009-08-31 20:15 dir1 . . . drwxr-xr-x 2 phys210t ugrad 4096 2009-09-15 15:33 Templates -rw-r--r-- 1 phys210t ugrad 29 2009-09-16 14:43 thedate drwxr-xr-x 2 phys210t ugrad 4096 2009-09-15 15:33 Videos One particularly interesting/useful local variable, PS1 (P-S-one), defines the bash prompt - in these notes I'm pretending that my standard prompt is '% ', but in reality its like yours phys210t@hyper ~]$ Display the value of PS1 phys210t@hyper ~]$ echo $PS1 [\u@\h \W]$ This output is probably not very intelligible, but if you want the full details see the appropriate section of the online bash manual at http://www.gnu.org/software/bash/manual/bashref.html#Printing-a-Prompt Let's set the prompt to '% ' phys210t@hyper ~]$ PS1='% ' % If you want to get it back to the default, source your ~/.bashrc % source ~/.bashrc [phys210t@hyper ~]$ ------------------------------------------------------------------------- 2b) Environment (Global) variables ------------------------------------------------------------------------- This type of variable is a little more interesting. First, you can actually get a listing of all currently defined environment (hereafter abbreviated 'env') variables (hereafter abbreviated 'vars', using env % env TERM=xterm SHELL=/bin/bash XDG_SESSION_COOKIE=dd7960f4980905b6f1adf1bb4a82e093-1253133378.882715-1343196034 SSH_CLIENT=127.0.1.1 51674 22 SSH_TTY=/dev/pts/42 HISTFILESIZE=1000 USER=phys210t MAIL=/var/mail/phys210t PATH=.:/home2/phys210t/bin:/home/phys210/bin:/etc:/usr/etc:/usr/ucb:/bin:/usr/bin:/usr/local/bin PWD=/home2/phys210t LANG=en_US.UTF-8 HISTCONTROL=ignoredups SHLVL=1 HOME=/home2/phys210t LOGNAME=phys210t SSH_CONNECTION=127.0.1.1 51674 127.0.1.1 22 _=/usr/bin/env Note that, by convention, env vars have all-upper-case names. Also note that _ is an env var, and that evaluating it at the shell prompt is the same as executing env % $_ TERM=xterm SHELL=/bin/bash . . . HOME=/home2/phys210t LOGNAME=phys210t SSH_CONNECTION=127.0.1.1 51674 127.0.1.1 22 _=/usr/bin/env Also note 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 /home2/phys210t % printenv HOME USER LOGNAME /home2/phys210t phys210t phys210t 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 % 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 % 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 1 indicating that this is a "1st-level" shell. Now start up a NEW bash in the original bash % bash % It's hard to tell that anything happened. But check the value of SHLVL % printenv SHLVL 2 so this is a "2nd-level" shell, which makes sense. Now, when we started the new, 2nd-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 % printenv 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, hard to tell anything happened except that 'exit' is echoed, and SHLVL is back to 1 % printenv SHLVL 1 You'll get more familiar with the use of shell variables when we start writing bash scripts and functions ------------------------------------------------------------------------- 3) 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! % ls A goldeneye prosiness abbas gonadotropic prostatodynia abettal gonococcus protectant ablation goosegirl protestation abortiveness gormaw protococcal . . . Glossotherium promenade zoomantist glume pronaos zoospore glycogenize propagator zygal gnathobasic propiolate zymologic goanna proprietress Godforsaken prorogate Now, let's select various sets of filenames using pattern matching Get a listing of all files whose names ... i) ... begin with z % ls z* zabtie zenithward zoa zoomantist zygal zarabanda zimentwater zonoplacental zoospore zymologic ii) ... 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 iii) ... end with z % ls *z berkowitz bruzz untz iv) ... are three characters long % ls ??? ask bat icy jib Ker neo nix old Ona Ova ree she vex zoa v) ... begin and end with a vowel % ls [aAeEiIoOuU]*[aAeEiIoOuU] academite asthenia impartance oxyphile aceanthrene athlete impendence ozonoscope acetylsalicylate attune improve Uintatheriidae . . . arthriticine Idiogastra overturnable uranite aschaffite Ilpirra Ovula urubu Asperugo Imerina oxane usucaptable assassinate immotile oxyaphia vi) ... begin and end with a consonant, note consonant = not a vowel % ls [^aAeEiIoOuU]*[^aAeEiIoOuU] babblishly Hippotigris radiator bacchanalianly histiocytic radiology backfall histotrophy raffishly . . . hexadecanoic quinquagenarian zoomantist hidalgoism quintillion zygal hierophantes rabbinistical zymologic Hippeastrum rachiometer vii) ... begin with an a end with a y and have 6 characters % ls a????y archly assify autecy EXERCISE: Try some of your own! ------------------------------------------------------------------------- 4) HISTORY/EVENTS As mentioned in class, 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. ------------------------------------------------------------------------- 5) STANDARD INPUT and STANDARD OUTPUT Recall that the standard input (stdin) is the default source of input for many Unix/Linux commands, and that standard output (stdout) is the default destination of output for many commands. Both are normally "tied" to the terminal, as best 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). ------------------------------------------------------------------------- 6) OUTPUT REDIRECTION and OUTPUT APPEND REDIRECTION This is an important topic, and we've already used output redirection in a couple of instances. Let's work through a few more examples of the two types of output redirection OUTPUT REDIRECTION Go to your home, and make a directory called redirect, change to it and verify that you're there % cd; mkdir redirect; cd redirect; pwd /home2/phys210t/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 % 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 more % 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 -rw-r--r-- 1 phys210t ugrad 250 2009-09-16 20:54 fireice -rw-r--r-- 1 phys210t ugrad 0 2009-09-16 20:54 ls-output -rw-r--r-- 1 phys210t ugrad 614 2009-09-16 20:54 night -rw-r--r-- 1 phys210t ugrad 539 2009-09-16 20:54 pools -rw-r--r-- 1 phys210t ugrad 752 2009-09-16 20:54 road -rw-r--r-- 1 phys210t ugrad 555 2009-09-16 20:54 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. ------------------------------------------------------------------------- 7) INPUT REDIRECTION & PIPES Change to your home directory, create the directory numbers, change to numbers, and verify that you are there % cd; mkdir numbers; cd numbers; pwd 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 sort is a powerful Unix 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 i) 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) ii) Sort the lines is alphabetical order (case insensitive on hyper) iii) 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. sort ALWAYS outputs to standard output, so if we want to save the sorted values, we will also need to use 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. So we have 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? 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 ------------------------------------------------------------------------- 8) GREP AND REGULAR EXPRESSIONS As mentioned in class, 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 phys210t replaced with your login) when you generate a long listing for the the directory % ls -l -rw-r--r-- 1 phys210t ugrad 2662 2009-09-16 20:28 poems Now let's use grep to display all the lines in poems that ... i) ... contain the word 'the' (case sensitive) - note that the % 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 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 ii) ... 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, iii) ... start with either 'I' or 'F' (no whitespace 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, iv) ... 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, v) ... 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). vi) ... 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 a lot of blank lines on the screen at this point. How many? Again, pipe the output into wc -l % grep '^ [ ]*$' poems | wc -l 24 OK, two more examples that may help you with the homework vii) ... 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 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 viii) ... 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: = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 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 Look in the history for grep commands themselves % 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 Look in the history for command-lines that begin with cd. Note the construction to match the command-line numbers, as well as the whitespace around the numbers % 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 . Look for environment vars whose names begin with 'SSH' env | grep '^SSH' SSH_CLIENT=142.103.234.164 57068 22 SSH_TTY=/dev/pts/24 SSH_CONNECTION=142.103.234.164 57068 142.103.236.100 22 Look for environment vars or values that contain $LOGNAME env | grep $LOGNAME OLDPWD=/home2/phys210t USER=phys210t MAIL=/var/mail/phys210t PATH=.:/home2/phys210t/bin:/home/phys210/bin:/etc:/usr/etc:/usr/ucb:/bin:/usr/bin:/usr/local/bin PWD=/home2/phys210t/grep HOME=/home2/phys210t LOGNAME=phys210t Whew!! We're done ------------------------------------------------------------------------- 9) ALL THOSE QUOTES We'll keep this section brief since we'll be discussing the various types of quotes when we talk about shell programming. So we'll simply work through the examples from the notes. FORWARD QUOTES Recall that these quotes inhibit shell evaluation of any and all special characters and/or constructs: % 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 the "looks inside" them and evaluates i) any references to the values of shell variables ii) anything within back-quotes (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 when you define 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/phys210t/hw1' BACKWARD QUOTES Recall that these quotes (backticks) provide the useful and 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 Wed Sep 16 21:18:57 PDT 2009 % thedate=`date` % echo $thedate Wed Sep 16 21:19:15 PDT 2009 % which true /bin/true % file `which true` /bin/true: ELF 64-bit LSB executable, x86-64, ... % file `which true` `which false` /bin/true: ELF 64-bit LSB executable ... /bin/false: ELF 64-bit LSB executable ... ----------------------------------------------------------------------------- We've covered a lot of ground here, and rest assured that you're well on your way to becoming a Unix/Linux guru! -----------------------------------------------------------------------------