~~~
nines = []
sums = []
@@ -156,7 +154,7 @@ for i in range(1, 10):
for i in range(len(nines)):
print '%.18f %.18f' % (nines[i], sums[i])
~~~
-
+{:class="in"}
The loop runs over the integers from 1 to 9 inclusive.
Using those values, we create the numbers 0.9, 0.09, 0.009, and so on, and put them in the list `vals`.
diff --git a/novice/git/01-backup.md b/novice/git/01-backup.md
index 7e4e2307b..e49cdcaa2 100644
--- a/novice/git/01-backup.md
+++ b/novice/git/01-backup.md
@@ -34,14 +34,13 @@ The first time we use Git on a new machine,
we need to configure a few things.
Here's how Dracula sets up his new laptop:
-
~~~
$ git config --global user.name "Vlad Dracula"
$ git config --global user.email "vlad@tran.sylvan.ia"
$ git config --global color.ui "auto"
$ git config --global core.editor "nano"
~~~
-
+{:class="in"}
(Please use your own name and email address instead of Dracula's,
and please make sure you choose an editor that's actually on your system,
@@ -66,44 +65,39 @@ Once Git is configured,
we can start using it.
Let's create a directory for our work:
-
+{:class="in"}
~~~
# On branch master
#
@@ -125,7 +117,7 @@ $ git status
#
nothing to commit (create/copy files and use "git add" to track)
~~~
-
+{:class="out"}
#### Tracking Changes to Files
@@ -135,52 +127,44 @@ about the Red Planet's suitability as a base.
you can use whatever editor you like.
In particular, this does not have to be the core.editor you set globally earlier.)
-
+{:class="in"}
~~~
# On branch master
#
@@ -192,26 +176,23 @@ $ git status
# mars.txt
nothing added to commit but untracked files present (use "git add" to track)
~~~
-
+{:class="out"}
The "untracked files" message means that there's a file in the directory
that Git isn't keeping track of.
We can tell Git that it should do so using `git add`:
-
+{:class="in"}
~~~
# On branch master
#
@@ -223,25 +204,23 @@ $ git status
# new file: mars.txt
#
~~~
-
+{:class="out"}
Git now knows that it's supposed to keep track of `mars.txt`,
but it hasn't yet recorded any changes for posterity as a commit.
To get it to do that,
we need to run one more command:
-
+{:class="in"}
~~~
[master (root-commit) f22b25e] Starting to think about Mars
1 file changed, 1 insertion(+)
create mode 100644 mars.txt
~~~
-
+{:class="out"}
When we run `git commit`,
Git takes everything we have told it to save by using `git add`
@@ -258,28 +237,24 @@ so that we can write a longer message.
If we run `git status` now:
-
+{:class="in"}
~~~
# On branch master
nothing to commit, working directory clean
~~~
-
+{:class="out"}
it tells us everything is up to date.
If we want to know what we've done recently,
we can ask Git to show us the project's history using `git log`:
-
+{:class="in"}
~~~
commit f22b25e3233b4645dabd0d81e651fe074bd8e73b
Author: Vlad Dracula
@@ -287,7 +262,7 @@ Date: Thu Aug 22 09:51:46 2013 -0400
Starting to think about Mars
~~~
-
+{:class="out"}
`git log` lists all revisions made to a repository in reverse chronological order.
The listing for each revision includes
@@ -312,28 +287,24 @@ Now suppose Dracula adds more information to the file.
(Again, we'll edit with `nano` and then `cat` the file to show its contents;
you may use a different editor, and don't need to `cat`.)
-
+{:class="in"}
~~~
Cold and dry, but everything is my favorite color
The two moons may be a problem for Wolfman
~~~
-
+{:class="out"}
When we run `git status` now,
it tells us that a file it already knows about has been modified:
-
+{:class="in"}
~~~
# On branch master
# Changes not staged for commit:
@@ -344,7 +315,7 @@ $ git status
#
no changes added to commit (use "git add" and/or "git commit -a")
~~~
-
+{:class="out"}
The last line is the key phrase:
"no changes added to commit".
@@ -357,12 +328,10 @@ which shows us the differences between
the current state of the file
and the most recently saved version:
-
+{:class="in"}
~~~
diff --git a/mars.txt b/mars.txt
index df0654a..315bf3a 100644
@@ -372,7 +341,7 @@ index df0654a..315bf3a 100644
Cold and dry, but everything is my favorite color
+The two moons may be a problem for Wolfman
~~~
-
+{:class="out"}
The output is cryptic because
it is actually a series of commands for tools like editors and `patch`
@@ -391,12 +360,10 @@ If we can break it down into pieces:
Let's commit our change:
-
+{:class="in"}
~~~
# On branch master
# Changes not staged for commit:
@@ -407,24 +374,22 @@ $ git commit -m "Concerns about Mars's moons on my furry friend"
#
no changes added to commit (use "git add" and/or "git commit -a")
~~~
-
+{:class="out"}
Whoops:
Git won't commit because we didn't use `git add` first.
Let's fix that:
-
~~~
$ git add mars.txt
$ git commit -m "Concerns about Mars's moons on my furry friend"
~~~
-
-
+{:class="in"}
~~~
[master 34961b1] Concerns about Mars's moons on my furry friend
1 file changed, 1 insertion(+)
~~~
-
+{:class="out"}
Git insists that we add files to the set we want to commit
before actually committing anything
@@ -453,25 +418,21 @@ and into long-term storage.
First,
we'll add another line to the file:
-
+{:class="in"}
~~~
Cold and dry, but everything is my favorite color
The two moons may be a problem for Wolfman
But the Mummy will appreciate the lack of humidity
~~~
-
-
+{:class="in"}
~~~
diff --git a/mars.txt b/mars.txt
index 315bf3a..b36abfd 100644
@@ -482,7 +443,7 @@ index 315bf3a..b36abfd 100644
The two moons may be a problem for Wolfman
+But the Mummy will appreciate the lack of humidity
~~~
-
+{:class="out"}
So far, so good:
we've added one line to the end of the file
@@ -490,12 +451,11 @@ we've added one line to the end of the file
Now let's put that change in the staging area
and see what `git diff` reports:
-
+{:class="in"}
~~~
diff --git a/mars.txt b/mars.txt
index 315bf3a..b36abfd 100644
@@ -520,47 +478,41 @@ index 315bf3a..b36abfd 100644
The two moons may be a problem for Wolfman
+But the Mummy will appreciate the lack of humidity
~~~
-
+{:class="out"}
it shows us the difference between
the last committed change
and what's in the staging area.
Let's save our changes:
-
+{:class="in"}
~~~
[master 005937f] Thoughts about the climate
1 file changed, 1 insertion(+)
~~~
-
+{:class="out"}
check our status:
-
+{:class="in"}
~~~
# On branch master
nothing to commit, working directory clean
~~~
-
+{:class="out"}
and look at the history of what we've done so far:
-
+{:class="in"}
~~~
commit 005937fbe2a98fb83f0ade869025dc2636b4dad5
Author: Vlad Dracula
@@ -580,7 +532,7 @@ Date: Thu Aug 22 09:51:46 2013 -0400
Starting to think about Mars
~~~
-
+{:class="out"}
#### Exploring History
@@ -589,12 +541,10 @@ we use `git diff` again,
but refer to old versions
using the notation `HEAD~1`, `HEAD~2`, and so on:
-
+{:class="in"}
~~~
diff --git a/mars.txt b/mars.txt
index 315bf3a..b36abfd 100644
@@ -605,13 +555,11 @@ index 315bf3a..b36abfd 100644
The two moons may be a problem for Wolfman
+But the Mummy will appreciate the lack of humidity
~~~
-
-
+{:class="in"}
~~~
diff --git a/mars.txt b/mars.txt
index df0654a..b36abfd 100644
@@ -622,7 +570,7 @@ index df0654a..b36abfd 100644
+The two moons may be a problem for Wolfman
+But the Mummy will appreciate the lack of humidity
~~~
-
+{:class="out"}
In this way,
we build up a chain of revisions.
@@ -643,12 +591,10 @@ Our first commit was given the ID
f22b25e3233b4645dabd0d81e651fe074bd8e73b,
so let's try this:
-
+{:class="in"}
~~~
diff --git a/mars.txt b/mars.txt
index df0654a..b36abfd 100644
@@ -659,18 +605,16 @@ index df0654a..b36abfd 100644
+The two moons may be a problem for Wolfman
+But the Mummy will appreciate the lack of humidity
~~~
-
+{:class="out"}
That's the right answer,
but typing random 40-character strings is annoying,
so Git lets us use just the first few:
-
+{:class="in"}
~~~
diff --git a/mars.txt b/mars.txt
index df0654a..b36abfd 100644
@@ -681,7 +625,7 @@ index df0654a..b36abfd 100644
+The two moons may be a problem for Wolfman
+But the Mummy will appreciate the lack of humidity
~~~
-
+{:class="out"}
#### Recovering Old Versions
@@ -690,27 +634,23 @@ we can save changes to files and see what we've changed---how
can we restore older versions of things?
Let's suppose we accidentally overwrite our file:
-
+{:class="in"}
~~~
# On branch master
# Changes not staged for commit:
@@ -721,24 +661,22 @@ $ git status
#
no changes added to commit (use "git add" and/or "git commit -a")
~~~
-
+{:class="out"}
We can put things back the way they were
by using `git checkout`:
-
+{:class="in"}
~~~
Cold and dry, but everything is my favorite color
The two moons may be a problem for Wolfman
But the Mummy will appreciate the lack of humidity
~~~
-
+{:class="out"}
As you might guess from its name,
`git checkout` checks out (i.e., restores) an old version of a file.
@@ -748,11 +686,10 @@ which is the last saved revision.
If we want to go back even further,
we can use a revision identifier instead:
-
~~~
$ mkdir results
$ touch a.dat b.dat c.dat results/a.out results/b.out
~~~
-
+{:class="in"}
and see what Git says:
-
+{:class="in"}
~~~
# On branch master
# Untracked files:
@@ -822,7 +755,7 @@ $ git status
# results/
nothing added to commit but untracked files present (use "git add" to track)
~~~
-
+{:class="out"}
Putting these files under version control would be a waste of disk space.
What's worse,
@@ -831,18 +764,16 @@ so let's tell Git to ignore them.
We do this by creating a file in the root directory of our project called `.gitignore`.
-
+{:class="in"}
~~~
# On branch master
# Untracked files:
@@ -866,7 +795,7 @@ $ git status
# .gitignore
nothing added to commit but untracked files present (use "git add" to track)
~~~
-
+{:class="out"}
The only thing Git notices now is the newly-created `.gitignore` file.
You might think we wouldn't want to track it,
@@ -874,47 +803,41 @@ but everyone we're sharing our repository with will probably want to ignore
the same things that we're ignoring.
Let's add and commit `.gitignore`:
-
~~~
$ git add .gitignore
$ git commit -m "Add the ignore file"
$ git status
~~~
-
-
+{:class="in"}
~~~
# On branch master
nothing to commit, working directory clean
~~~
-
+{:class="out"}
As a bonus,
using `.gitignore` helps us avoid accidentally adding files to the repository that we don't want.
-
+{:class="in"}
~~~
The following paths are ignored by one of your .gitignore files:
a.dat
Use -f if you really want to add them.
fatal: no files added
~~~
-
+{:class="out"}
If we really want to override our ignore settings,
we can use `git add -f` to force Git to add something.
We can also always see the status of ignored files if we want:
-
+{:class="in"}
~~~
# On branch master
# Ignored files:
@@ -927,7 +850,7 @@ $ git status --ignored
nothing to commit, working directory clean
~~~
-
+{:class="out"}
@@ -959,7 +882,6 @@ nothing to commit, working directory clean
2. The following sequence of commands creates one Git repository inside another:
-
~~~
cd # return to home directory
mkdir alpha # make a new directory alpha
@@ -969,7 +891,7 @@ nothing to commit, working directory clean
cd beta # go into alpha/beta
git init # make the beta sub-directory a Git repository
~~~
-
+ {:class="in"}
Why is it a bad idea to do this?
diff --git a/novice/git/02-collab.md b/novice/git/02-collab.md
index 070ab0a36..002cd4885 100644
--- a/novice/git/02-collab.md
+++ b/novice/git/02-collab.md
@@ -43,13 +43,12 @@ GitHub displays a page with a URL and some information on how to configure your
This effectively does the following on GitHub's servers:
-
~~~
$ mkdir planets
$ cd planets
$ git init
~~~
-
+{:class="in"}
Our local repository still contains our earlier work on `mars.txt`,
but the remote repository on GitHub doesn't contain any files yet:
@@ -74,28 +73,25 @@ Copy that URL from the browser,
go into the local `planets` repository,
and run this command:
-
~~~
$ git remote add origin https://github.com/vlad/planets
~~~
-
+{:class="in"}
Make sure to use the URL for your repository rather than Vlad's:
the only difference should be your username instead of `vlad`.
We can check that the command has worked by running `git remote -v`:
-
~~~
$ git remote -v
~~~
-
-
+{:class="in"}
~~~
origin https://github.com/vlad/planets.git (push)
origin https://github.com/vlad/planets.git (fetch)
~~~
-
+{:class="out"}
The name `origin` is a local nickname for your remote repository:
we could use something else if we wanted to,
@@ -105,12 +101,10 @@ Once the nickname `origin` is set up,
this command will push the changes from our local repository
to the repository on GitHub:
-
~~~
$ git push origin master
~~~
-
-
+{:class="in"}
~~~
Counting objects: 9, done.
Delta compression using up to 4 threads.
@@ -121,7 +115,7 @@ To https://github.com/vlad/planets
* [new branch] master -> master
Branch master set up to track remote branch master from origin.
~~~
-
+{:class="out"}
Our local and remote repositories are now in this state:
@@ -135,18 +129,16 @@ Our local and remote repositories are now in this state:
We can pull changes from the remote repository to the local one as well:
-
~~~
$ git pull origin master
~~~
-
-
+{:class="in"}
~~~
From https://github.com/vlad/planets
* branch master -> FETCH_HEAD
Already up-to-date.
~~~
-
+{:class="out"}
Pulling has no effect in this case
because the two repositories are already synchronized.
@@ -162,12 +154,11 @@ don't make `tmp` a subdirectory of the existing repository).
Instead of creating a new repository here with `git init`,
we will [clone](../../gloss.html#repository-clone) the existing repository from GitHub:
-
~~~
$ cd /tmp
$ git clone https://github.com/vlad/planets.git
~~~
-
+{:class="in"}
`git clone` creates a fresh local copy of a remote repository.
(We did it in `/tmp` or some other directory so that we don't overwrite our existing `planets` directory.)
@@ -177,39 +168,33 @@ Our computer now has two copies of the repository:
Let's make a change in the copy in `/tmp/planets`:
-
~~~
$ cd /tmp/planets
$ nano pluto.txt
$ cat pluto.txt
~~~
-
-
+{:class="in"}
~~~
It is so a planet!
~~~
-
-
+{:class="out"}
~~~
$ git add pluto.txt
$ git commit -m "Some notes about Pluto"
~~~
-
-
+{:class="in"}
~~~
1 file changed, 1 insertion(+)
create mode 100644 pluto.txt
~~~
-
+{:class="out"}
then push the change to GitHub:
-
~~~
$ git push origin master
~~~
-
-
+{:class="in"}
~~~
Counting objects: 4, done.
Delta compression using up to 4 threads.
@@ -219,7 +204,7 @@ Total 3 (delta 0), reused 0 (delta 0)
To https://github.com/vlad/planets.git
9272da5..29aba7c master -> master
~~~
-
+{:class="out"}
Note that we didn't have to create a remote called `origin`:
Git does this automatically,
@@ -234,13 +219,11 @@ Our three repositories now look like this:
We can now download changes into the original repository on our machine:
-
~~~
$ cd ~/planets
$ git pull origin master
~~~
-
-
+{:class="in"}
~~~
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
@@ -254,7 +237,7 @@ Fast-forward
1 file changed, 1 insertion(+)
create mode 100644 pluto.txt
~~~
-
+{:class="out"}
which gives us this:
diff --git a/novice/git/03-conflict.md b/novice/git/03-conflict.md
index b1360f239..20c002cec 100644
--- a/novice/git/03-conflict.md
+++ b/novice/git/03-conflict.md
@@ -25,56 +25,48 @@ The file `mars.txt` currently looks like this
in both local copies of our `planets` repository
(the one in our home directory and the one in `/tmp`):
-
~~~
$ cat mars.txt
~~~
-
-
+{:class="in"}
~~~
Cold and dry, but everything is my favorite color
The two moons may be a problem for Wolfman
But the Mummy will appreciate the lack of humidity
~~~
-
+{:class="out"}
Let's add a line to the copy under our home directory:
-
~~~
$ nano mars.txt
$ cat mars.txt
~~~
-
-
+{:class="in"}
~~~
Cold and dry, but everything is my favorite color
The two moons may be a problem for Wolfman
But the Mummy will appreciate the lack of humidity
This line added to our home copy
~~~
-
+{:class="out"}
and then push the change to GitHub:
-
~~~
$ git add mars.txt
$ git commit -m "Adding a line in our home copy"
~~~
-
-
+{:class="in"}
~~~
[master 5ae9631] Adding a line in our home copy
1 file changed, 1 insertion(+)
~~~
-
-
+{:class="out"}
~~~
$ git push origin master
~~~
-
-
+{:class="in"}
~~~
Counting objects: 5, done.
Delta compression using up to 4 threads.
@@ -84,7 +76,7 @@ Total 3 (delta 1), reused 0 (delta 0)
To https://github.com/vlad/planets
29aba7c..dabb4c8 master -> master
~~~
-
+{:class="out"}
Our repositories are now in this state:
@@ -94,45 +86,39 @@ Now let's switch to the copy under `/tmp`
and make a different change there
*without* updating from GitHub:
-
~~~
$ cd /tmp/planets
$ nano mars.txt
$ cat mars.txt
~~~
-
-
+{:class="in"}
~~~
Cold and dry, but everything is my favorite color
The two moons may be a problem for Wolfman
But the Mummy will appreciate the lack of humidity
We added a different line in the temporary copy
~~~
-
+{:class="out"}
We can commit the change locally:
-
~~~
$ git add mars.txt
$ git commit -m "Adding a line in the temporary copy"
~~~
-
-
+{:class="in"}
~~~
[master 07ebc69] Adding a line in the temporary copy
1 file changed, 1 insertion(+)
~~~
-
+{:class="out"}
but Git won't let us push it to GitHub:
-
~~~
$ git push origin master
~~~
-
-
+{:class="in"}
~~~
To https://github.com/vlad/planets.git
! [rejected] master -> master (non-fast-forward)
@@ -142,7 +128,7 @@ hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
~~~
-
+{:class="out"}
Git detects that the changes made in one copy overlap with those made in the other
and stops us from trampling on our previous work.
@@ -151,12 +137,10 @@ What we have to do is pull the changes from GitHub,
and then push that.
Let's start by pulling:
-
~~~
$ git pull origin master
~~~
-
-
+{:class="in"}
~~~
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
@@ -168,17 +152,15 @@ Auto-merging mars.txt
CONFLICT (content): Merge conflict in mars.txt
Automatic merge failed; fix conflicts and then commit the result.
~~~
-
+{:class="out"}
`git pull` tells us there's a conflict,
and marks that conflict in the affected file:
-
~~~
$ cat mars.txt
~~~
-
-
+{:class="in"}
~~~
Cold and dry, but everything is my favorite color
The two moons may be a problem for Wolfman
@@ -189,7 +171,7 @@ We added a different line in the temporary copy
This line added to our home copy
>>>>>>> dabb4c8c450e8475aee9b14b4383acc99f42af1d
~~~
-
+{:class="out"}
Our change---the one in `HEAD`---is preceded by `<<<<<<<`.
Git has then inserted `=======` as a separator between the conflicting changes
@@ -206,31 +188,27 @@ write something new to replace both,
or get rid of the change entirely.
Let's replace both so that the file looks like this:
-
~~~
$ cat mars.txt
~~~
-
-
+{:class="in"}
~~~
Cold and dry, but everything is my favorite color
The two moons may be a problem for Wolfman
But the Mummy will appreciate the lack of humidity
We removed the conflict on this line
~~~
-
+{:class="out"}
To finish merging,
we add `mars.txt` to the changes being made by the merge
and then commit:
-
~~~
$ git add mars.txt
$ git status
~~~
-
-
+{:class="in"}
~~~
# On branch master
# All conflicts fixed but you are still merging.
@@ -241,17 +219,15 @@ $ git status
# modified: mars.txt
#
~~~
-
-
+{:class="out"}
~~~
$ git commit -m "Merging changes from GitHub"
~~~
-
-
+{:class="in"}
~~~
[master 2abf2b1] Merging changes from GitHub
~~~
-
+{:class="out"}
Our repositories now look like this:
@@ -259,12 +235,10 @@ Our repositories now look like this:
so we push our changes to GitHub:
-
~~~
$ git push origin master
~~~
-
-
+{:class="in"}
~~~
Counting objects: 10, done.
Delta compression using up to 4 threads.
@@ -274,7 +248,7 @@ Total 6 (delta 2), reused 0 (delta 0)
To https://github.com/vlad/planets.git
dabb4c8..2abf2b1 master -> master
~~~
-
+{:class="out"}
to get this:
@@ -284,13 +258,11 @@ Git keeps track of what we've merged with what,
so we don't have to fix things by hand again
if we switch back to the repository in our home directory and pull from GitHub:
-
~~~
$ cd ~/planets
$ git pull origin master
~~~
-
-
+{:class="in"}
~~~
remote: Counting objects: 10, done.
remote: Compressing objects: 100% (4/4), done.
@@ -303,23 +275,21 @@ Fast-forward
mars.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
~~~
-
+{:class="out"}
we get the merged file:
-
~~~
$ cat mars.txt
~~~
-
-
+{:class="in"}
~~~
Cold and dry, but everything is my favorite color
The two moons may be a problem for Wolfman
But the Mummy will appreciate the lack of humidity
We removed the conflict on this line
~~~
-
+{:class="out"}
We don't need to merge again because GitHub knows someone has already done that.
diff --git a/novice/shell/01-filedir.md b/novice/shell/01-filedir.md
index 0f763dc20..b361c8b6b 100644
--- a/novice/shell/01-filedir.md
+++ b/novice/shell/01-filedir.md
@@ -26,11 +26,10 @@ Several commands are frequently used to create, inspect, rename, and delete file
To start exploring them,
let's open a shell window:
-
~~~
$
~~~
-
+{:class="in"}
The dollar sign is a [prompt](../../gloss.html#prompt),
which shows us that the shell is waiting for input;
@@ -42,16 +41,14 @@ The command's output is the ID of the current user,
i.e.,
it shows us who the shell thinks we are:
-
~~~
$ whoami
~~~
-
-
+{:class="in"}
~~~
vlad
~~~
-
+{:class="out"}
More specifically, when we type `whoami` the shell:
@@ -73,16 +70,14 @@ Here,
the computer's response is `/users/vlad`,
which is Vlad's [home directory](../../gloss.html#home-directory):
-
~~~
$ pwd
~~~
-
-
+{:class="in"}
~~~
/users/vlad
~~~
-
+{:class="out"}
> #### Alphabet Soup
>
@@ -136,18 +131,16 @@ which is why `vlad` is the last part of the directory's name.
Let's see what's in Vlad's home directory by running `ls`,
which stands for "listing":
-
~~~
$ ls
~~~
-
-
+{:class="in"}
~~~
bin data mail music
notes.txt papers pizza.cfg solar
solar.pdf swc
~~~
-
+{:class="out"}

@@ -156,18 +149,16 @@ arranged neatly into columns.
We can make its output more comprehensible by using the [flag](../../gloss.html#command-line-flag) `-F`,
which tells `ls` to add a trailing `/` to the names of directories:
-
~~~
$ ls -F
~~~
-
-
+{:class="in"}
~~~
bin/ data/ mail/ music/
notes.txt papers/ pizza.cfg solar/
solar.pdf swc/
~~~
-
+{:class="out"}
Here,
we can see that `/users/vlad` contains seven [sub-directories](../../gloss.html#sub-directory).
@@ -206,17 +197,15 @@ the command `ls` with the parameters `-F` and `data`.
The second parameter—the one *without* a leading dash—tells `ls` that
we want a listing of something other than our current working directory:
-
~~~
$ ls -F data
~~~
-
-
+{:class="in"}
~~~
amino-acids.txt elements/ morse.txt
pdb/ planets.txt sunspot.txt
~~~
-
+{:class="out"}
The output shows us that there are four text files and two sub-sub-directories.
Organizing things hierarchically in this way helps us keep track of our work:
@@ -234,17 +223,15 @@ rather than from the root of the file system.
If we run `ls -F /data` (*with* a leading slash) we get a different answer,
because `/data` is an [absolute path](../../gloss.html#absolute-path):
-
~~~
$ ls -F /data
~~~
-
-
+{:class="in"}
~~~
access.log backup/ hardware.cfg
network.cfg
~~~
-
+{:class="out"}
The leading `/` tells the computer to follow the path from the root of the filesystem,
so it always refers to exactly one directory,
@@ -255,28 +242,24 @@ Before we do this,
`pwd` shows us that we're in `/users/vlad`,
and `ls` without any parameters shows us that directory's contents:
-
~~~
$ pwd
~~~
-
-
+{:class="in"}
~~~
/users/vlad
~~~
-
-
+{:class="out"}
~~~
$ ls
~~~
-
-
+{:class="in"}
~~~
bin/ data/ mail/ music/
notes.txt papers/ pizza.cfg solar/
solar.pdf swc/
~~~
-
+{:class="out"}
We can use `cd` followed by a directory name to change our working directory.
`cd` stands for "change directory",
@@ -284,11 +267,10 @@ which is a bit misleading:
the command doesn't change the directory,
it changes the shell's idea of what directory we are in.
-
~~~
$ cd data
~~~
-
+{:class="in"}
`cd` doesn't print anything,
but if we run `pwd` after it, we can see that we are now in `/users/vlad/data`.
@@ -296,55 +278,47 @@ If we run `ls` without parameters now,
it lists the contents of `/users/vlad/data`,
because that's where we now are:
-
~~~
$ pwd
~~~
-
-
+{:class="in"}
~~~
/users/vlad/data
~~~
-
-
+{:class="out"}
~~~
$ ls
~~~
-
-
+{:class="in"}
~~~
amino-acids.txt elements/ morse.txt
pdb/ planets.txt sunspot.txt
~~~
-
+{:class="out"}
We now know how to go down the directory tree:
how do we go up?
We could use an absolute path:
-
~~~
$ cd /users/vlad
~~~
-
+{:class="in"}
but it's almost always simpler to use `cd ..` to go up one level:
-
~~~
$ pwd
~~~
-
-
+{:class="in"}
~~~
/users/vlad/data
~~~
-
-
+{:class="out"}
~~~
$ cd ..
~~~
-
+{:class="in"}
`..` is a special directory name meaning
"the directory containing this one",
@@ -353,32 +327,28 @@ the [parent](../../gloss.html#parent-directory) of the current directory.
Sure enough,
if we run `pwd` after running `cd ..`, we're back in `/users/vlad`:
-
~~~
$ pwd
~~~
-
-
+{:class="in"}
~~~
/users/vlad
~~~
-
+{:class="out"}
The special directory `..` doesn't usually show up when we run `ls`.
If we want to display it, we can give `ls` the `-a` flag:
-
~~~
$ ls -F -a
~~~
-
-
+{:class="in"}
~~~
./ ../ bin/ data/
mail/ music/ notes.txt papers/
pizza.cfg solar/ solar.pdf swc/
~~~
-
+{:class="out"}
`-a` stands for "show all";
it forces `ls` to show us file and directory names that begin with `.`,
@@ -437,30 +407,27 @@ All 1520 files will go into the same directory.
If she is in her home directory,
Nelle can see what files she has using the command:
-
~~~
$ ls north-pacific-gyre/2012-07-03/
~~~
-
+{:class="in"}
This is a lot to type,
but she can let the shell do most of the work.
If she types:
-
~~~
$ ls no
~~~
-
+{:class="in"}
and then presses tab,
the shell automatically completes the directory name for her:
-
~~~
$ ls north-pacific-gyre/
~~~
-
+{:class="in"}
If she presses tab again,
Bash will add `2012-07-03/` to the command,
diff --git a/novice/shell/02-create.md b/novice/shell/02-create.md
index 1c590951b..08862d2c6 100644
--- a/novice/shell/02-create.md
+++ b/novice/shell/02-create.md
@@ -19,37 +19,32 @@ Let's go back to Vlad's home directory,
`/users/vlad`,
and use `ls -F` to see what it contains:
-
~~~
$ pwd
~~~
-
-
+{:class="in"}
~~~
/users/vlad
~~~
-
-
+{:class="out"}
~~~
$ ls -F
~~~
-
-
+{:class="in"}
~~~
bin/ data/ mail/ music/
notes.txt papers/ pizza.cfg solar/
solar.pdf swc/
~~~
-
+{:class="out"}
Let's create a new directory called `thesis` using the command `mkdir thesis`
(which has no output):
-
~~~
$ mkdir thesis
~~~
-
+{:class="in"}
As you might (or might not) guess from its name,
`mkdir` means "make directory".
@@ -57,36 +52,32 @@ Since `thesis` is a relative path
(i.e., doesn't have a leading slash),
the new directory is made below the current working directory:
-
~~~
$ ls -F
~~~
-
-
+{:class="in"}
~~~
bin/ data/ mail/ music/
notes.txt papers/ pizza.cfg solar/
solar.pdf swc/ thesis/
~~~
-
+{:class="out"}
However, there's nothing in it yet:
-
~~~
$ ls -F thesis
~~~
-
+{:class="in"}
Let's change our working directory to `thesis` using `cd`,
then run a text editor called Nano to create a file called `draft.txt`:
-
~~~
$ cd thesis
$ nano draft.txt
~~~
-
+{:class="in"}
> #### Which Editor?
>
@@ -119,35 +110,31 @@ we can use Control-X to quit the editor and return to the shell.
`nano` doesn't leave any output on the screen after it exits,
but `ls` now shows that we have created a file called `draft.txt`:
-
~~~
$ ls
~~~
-
-
+{:class="in"}
~~~
draft.txt
~~~
-
+{:class="out"}
Let's tidy up by running `rm draft.txt`:
-
~~~
$ rm draft.txt
~~~
-
+{:class="in"}
This command removes files ("rm" is short for "remove").
If we run `ls` again,
its output is empty once more,
which tells us that our file is gone:
-
~~~
$ ls
~~~
-
+{:class="in"}
> #### Deleting Is Forever
>
@@ -160,46 +147,39 @@ $ ls
Let's re-create that file
and then move up one directory to `/users/vlad` using `cd ..`:
-
~~~
$ pwd
~~~
-
-
+{:class="in"}
~~~
/users/vlad/thesis
~~~
-
-
+{:class="out"}
~~~
$ nano draft.txt
$ ls
~~~
-
-
+{:class="in"}
~~~
draft.txt
~~~
-
-
+{:class="out"}
~~~
$ cd ..
~~~
-
+{:class="in"}
If we try to remove the entire `thesis` directory using `rm thesis`,
we get an error message:
-
~~~
$ rm thesis
~~~
-
-
+{:class="in"}
~~~
rm: cannot remove `thesis': Is a directory
~~~
-
+{:class="err"}
This happens because `rm` only works on files, not directories.
The right command is `rmdir`,
@@ -207,34 +187,30 @@ which is short for "remove directory".
It doesn't work yet either, though,
because the directory we're trying to remove isn't empty:
-
~~~
$ rmdir thesis
~~~
-
-
+{:class="in"}
~~~
rmdir: failed to remove `thesis': Directory not empty
~~~
-
+{:class="err"}
This little safety feature can save you a lot of grief,
particularly if you are a bad typist.
To really get rid of `thesis` we must first delete the file `draft.txt`:
-
~~~
$ rm thesis/draft.txt
~~~
-
+{:class="in"}
The directory is now empty, so `rmdir` can delete it:
-
~~~
$ rmdir thesis
~~~
-
+{:class="in"}
> #### With Great Power Comes Great Responsibility
>
@@ -255,42 +231,36 @@ Let's create that directory and file one more time.
(Note that this time we're running `nano` with the path `thesis/draft.txt`,
rather than going into the `thesis` directory and running `nano` on `draft.txt` there.)
-
~~~
$ pwd
~~~
-
-
+{:class="in"}
~~~
/users/vlad
~~~
-
-
+{:class="out"}
~~~
$ mkdir thesis
~~~
-
-
+{:class="in"}
~~~
$ nano thesis/draft.txt
$ ls thesis
~~~
-
-
+{:class="in"}
~~~
draft.txt
~~~
-
+{:class="out"}
`draft.txt` isn't a particularly informative name,
so let's change the file's name using `mv`,
which is short for "move":
-
~~~
$ mv thesis/draft.txt thesis/quotes.txt
~~~
-
+{:class="in"}
The first parameter tells `mv` what we're "moving",
while the second is where it's to go.
@@ -300,16 +270,14 @@ which has the same effect as renaming the file.
Sure enough,
`ls` shows us that `thesis` now contains one file called `quotes.txt`:
-
~~~
$ ls thesis
~~~
-
-
+{:class="in"}
~~~
quotes.txt
~~~
-
+{:class="out"}
Just for the sake of inconsistency,
`mv` also works on directories—there is no separate `mvdir` command.
@@ -323,35 +291,31 @@ but put the file somewhere new.
In this case,
the directory name we use is the special directory name `.` that we mentioned earlier.
-
~~~
$ mv thesis/quotes.txt .
~~~
-
+{:class="in"}
The effect is to move the file from the directory it was in to the current working directory.
`ls` now shows us that `thesis` is empty:
-
~~~
$ ls thesis
~~~
-
+{:class="in"}
Further,
`ls` with a filename or directory name as a parameter only lists that file or directory.
We can use this to see that `quotes.txt` is still in our current directory:
-
~~~
$ ls quotes.txt
~~~
-
-
+{:class="in"}
~~~
quotes.txt
~~~
-
+{:class="out"}
The `cp` command works very much like `mv`,
except it copies a file instead of moving it.
@@ -359,17 +323,15 @@ We can check that it did the right thing using `ls`
with two paths as parameters—like most Unix commands,
`ls` can be given thousands of paths at once:
-
~~~
$ cp quotes.txt thesis/quotations.txt
$ ls quotes.txt thesis/quotations.txt
~~~
-
-
+{:class="in"}
~~~
quotes.txt thesis/quotations.txt
~~~
-
+{:class="out"}
To prove that we made a copy,
let's delete the `quotes.txt` file in the current directory
@@ -377,17 +339,15 @@ and then run that same `ls` again.
This time it tells us that it can't find `quotes.txt` in the current directory,
but it does find the copy in `thesis` that we didn't delete:
-
~~~
$ ls quotes.txt thesis/quotations.txt
~~~
-
-
+{:class="in"}
~~~
ls: cannot access quotes.txt: No such file or directory
thesis/quotations.txt
~~~
-
+{:class="err"}
> #### Another Useful Abbreviation
>
diff --git a/novice/shell/03-pipefilter.md b/novice/shell/03-pipefilter.md
index b976aa5f9..517e7a7b5 100644
--- a/novice/shell/03-pipefilter.md
+++ b/novice/shell/03-pipefilter.md
@@ -22,17 +22,15 @@ that contains six files describing some simple organic molecules.
The `.pdb` extension indicates that these files are in Protein Data Bank format,
a simple text format that specifies the type and position of each atom in the molecule.
-
~~~
$ ls molecules
~~~
-
-
+{:class="in"}
~~~
cubane.pdb ethane.pdb methane.pdb
octane.pdb pentane.pdb propane.pdb
~~~
-
+{:class="out"}
Let's go into that directory with `cd` and run the command `wc *.pdb`.
`wc` is the "word count" command:
@@ -40,13 +38,11 @@ it counts the number of lines, words, and characters in files.
The `*` in `*.pdb` matches zero or more characters,
so the shell turns `*.pdb` into a complete list of `.pdb` files:
-
~~~
$ cd molecules
$ wc *.pdb
~~~
-
-
+{:class="in"}
~~~
20 156 1158 cubane.pdb
12 84 622 ethane.pdb
@@ -56,7 +52,7 @@ $ wc *.pdb
15 111 825 propane.pdb
107 819 6081 total
~~~
-
+{:class="out"}
> #### Wildcards
>
@@ -85,12 +81,10 @@ $ wc *.pdb
If we run `wc -l` instead of just `wc`,
the output shows only the number of lines per file:
-
~~~
$ wc -l *.pdb
~~~
-
-
+{:class="in"}
~~~
20 cubane.pdb
12 ethane.pdb
@@ -100,7 +94,7 @@ $ wc -l *.pdb
15 propane.pdb
107 total
~~~
-
+{:class="out"}
We can also use `-w` to get only the number of words,
or `-c` to get only the number of characters.
@@ -110,11 +104,10 @@ It's an easy question to answer when there are only six files,
but what if there were 6000?
Our first step toward a solution is to run the command:
-
~~~
$ wc -l *.pdb > lengths
~~~
-
+{:class="in"}
The `>` tells the shell to [redirect](../../gloss.html#redirect) the command's output
to a file instead of printing it to the screen.
@@ -124,16 +117,14 @@ or overwrite the contents of that file if it does.
everything that `wc` would have printed has gone into the file `lengths` instead.)
`ls lengths` confirms that the file exists:
-
~~~
$ ls lengths
~~~
-
-
+{:class="in"}
~~~
lengths
~~~
-
+{:class="out"}
We can now send the content of `lengths` to the screen using `cat lengths`.
`cat` stands for "concatenate":
@@ -141,12 +132,10 @@ it prints the contents of files one after another.
There's only one file in this case,
so `cat` just shows us what it contains:
-
~~~
$ cat lengths
~~~
-
-
+{:class="in"}
~~~
20 cubane.pdb
12 ethane.pdb
@@ -156,18 +145,16 @@ $ cat lengths
15 propane.pdb
107 total
~~~
-
+{:class="out"}
Now let's use the `sort` command to sort its contents.
This does *not* change the file;
instead, it sends the sorted result to the screen:
-
~~~
$ sort lengths
~~~
-
-
+{:class="in"}
~~~
9 methane.pdb
12 ethane.pdb
@@ -177,7 +164,7 @@ $ sort lengths
30 octane.pdb
107 total
~~~
-
+{:class="out"}
We can put the sorted list of lines in another temporary file called `sorted-lengths`
by putting `> sorted-lengths` after the command,
@@ -185,17 +172,15 @@ just as we used `> lengths` to put the output of `wc` into `lengths`.
Once we've done that,
we can run another command called `head` to get the first few lines in `sorted-lengths`:
-
~~~
$ sort lengths > sorted-lengths
$ head -1 sorted-lengths
~~~
-
-
+{:class="in"}
~~~
9 methane.pdb
~~~
-
+{:class="out"}
Using the parameter `-1` with `head` tells it that
we only want the first line of the file;
@@ -210,16 +195,14 @@ even once you understand what `wc`, `sort`, and `head` do,
all those intermediate files make it hard to follow what's going on.
We can make it easier to understand by running `sort` and `head` together:
-
~~~
$ sort lengths | head -1
~~~
-
-
+{:class="in"}
~~~
9 methane.pdb
~~~
-
+{:class="out"}
The vertical bar between the two commands is called a [pipe](../../gloss.html#pipe).
It tells the shell that we want to use
@@ -233,16 +216,14 @@ we don't have to know or care.
We can use another pipe to send the output of `wc` directly to `sort`,
which then sends its output to `head`:
-
~~~
$ wc -l *.pdb | sort | head -1
~~~
-
-
+{:class="in"}
~~~
9 methane.pdb
~~~
-
+{:class="out"}
This is exactly like a mathematician nesting functions like *sin(πx)
2*
and saying "the square of the sine of *x* times π".
@@ -323,16 +304,14 @@ Nelle has run her samples through the assay machines
and created 1520 files in the `north-pacific-gyre/2012-07-03` directory described earlier.
As a quick sanity check, she types:
-
~~~
$ cd north-pacific-gyre/2012-07-03
$ wc -l *.txt
~~~
-
+{:class="in"}
The output is 1520 lines that look like this:
-
~~~
300 NENE01729A.txt
300 NENE01729B.txt
@@ -342,16 +321,14 @@ The output is 1520 lines that look like this:
300 NENE01812A.txt
... ...
~~~
-
+{:class="out"}
Now she types this:
-
~~~
$ wc -l *.txt | sort | head -5
~~~
-
-
+{:class="in"}
~~~
240 NENE02018B.txt
300 NENE01729A.txt
@@ -359,7 +336,7 @@ $ wc -l *.txt | sort | head -5
300 NENE01736A.txt
300 NENE01751A.txt
~~~
-
+{:class="out"}
Whoops: one of the files is 60 lines shorter than the others.
When she goes back and checks it,
@@ -369,12 +346,10 @@ and she forgot to reset it.
Before re-running that sample,
she checks to see if any files have too much data:
-
~~~
$ wc -l *.txt | sort | tail -5
~~~
-
-
+{:class="in"}
~~~
300 NENE02040A.txt
300 NENE02040B.txt
@@ -382,7 +357,7 @@ $ wc -l *.txt | sort | tail -5
300 NENE02043A.txt
300 NENE02043B.txt
~~~
-
+{:class="out"}
Those numbers look good—but what's that 'Z' doing there in the third-to-last line?
All of her samples should be marked 'A' or 'B';
@@ -390,16 +365,14 @@ by convention,
her lab uses 'Z' to indicate samples with missing information.
To find others like it, she does this:
-
~~~
$ ls *Z.txt
~~~
-
-
+{:class="in"}
~~~
NENE01971Z.txt NENE02040Z.txt
~~~
-
+{:class="out"}
Sure enough,
when she checks the log on her laptop,
diff --git a/novice/shell/04-loop.md b/novice/shell/04-loop.md
index 59bab5522..57fb98d55 100644
--- a/novice/shell/04-loop.md
+++ b/novice/shell/04-loop.md
@@ -22,19 +22,17 @@ When new files arrive,
we'd like to rename the existing ones to `original-basilisk.dat` and `original-unicorn.dat`.
We can't use:
-
~~~
$ mv *.dat original-*.dat
~~~
-
+{:class="in"}
because that would expand (in the two-file case) to:
-
~~~
$ mv basilisk.dat unicorn.dat
~~~
-
+{:class="in"}
This wouldn't back up our files:
it would replace the content of `unicorn.dat` with whatever's in `basilisk.dat`.
@@ -43,15 +41,13 @@ Instead, we can use a [loop](../../gloss.html#for-loop)
to do some operation once for each thing in a list.
Here's a simple example that displays the first three lines of each file in turn:
-
~~~
$ for filename in basilisk.dat unicorn.dat
> do
> head -3 $filename
> done
~~~
-
-
+{:class="in"}
~~~
COMMON NAME: basilisk
CLASSIFICATION: basiliscus vulgaris
@@ -60,7 +56,7 @@ COMMON NAME: unicorn
CLASSIFICATION: equus monoceros
UPDATED: 1738-11-24
~~~
-
+{:class="out"}
When the shell sees the keyword `for`,
it knows it is supposed to repeat a command (or group of commands) once for each thing in a list.
@@ -88,25 +84,23 @@ in order to make its purpose clearer to human readers.
The shell itself doesn't care what the variable is called;
if we wrote this loop as:
-
~~~
for x in basilisk.dat unicorn.dat
do
head -3 $x
done
~~~
-
+{:class="in"}
or:
-
~~~
for temperature in basilisk.dat unicorn.dat
do
head -3 $temperature
done
~~~
-
+{:class="in"}
it would work exactly the same way.
*Don't do this.*
@@ -116,7 +110,6 @@ increase the odds that the program won't do what its readers think it does.
Here's a slightly more complicated loop:
-
~~~
for filename in *.dat
do
@@ -124,7 +117,7 @@ do
head -100 $filename | tail -20
done
~~~
-
+{:class="in"}
The shell starts by expanding `*.dat` to create the list of files it will process.
The [loop body](../../gloss.html#loop-body)
@@ -132,26 +125,23 @@ then executes two commands for each of those files.
The first, `echo`, just prints its command-line parameters to standard output.
For example:
-
~~~
$ echo hello there
~~~
-
+{:class="in"}
prints:
-
~~~
hello there
~~~
-
+{:class="out"}
In this case,
since the shell expands `$filename` to be the name of a file,
`echo $filename` just prints the name of the file.
Note that we can't write this as:
-
~~~
for filename in *.dat
do
@@ -159,7 +149,7 @@ do
head -100 $filename | tail -20
done
~~~
-
+{:class="in"}
because then the first time through the loop,
when `$filename` expanded to `basilisk.dat`, the shell would try to run `basilisk.dat` as a program.
@@ -222,33 +212,30 @@ the `head` and `tail` combination selects lines 81-100 from whatever file is bei
Going back to our original file renaming problem,
we can solve it using this loop:
-
~~~
for filename in *.dat
do
mv $filename original-$filename
done
~~~
-
+{:class="in"}
This loop runs the `mv` command once for each filename.
The first time,
when `$filename` expands to `basilisk.dat`,
the shell executes:
-
~~~
mv basilisk.dat original-basilisk.dat
~~~
-
+{:class="in"}
The second time, the command is:
-
~~~
mv unicorn.dat original-unicorn.dat
~~~
-
+{:class="in"}
> #### Measure Twice, Run Once
>
@@ -285,7 +272,6 @@ she decides to build up the required commands in stages.
Her first step is to make sure that she can select the right files—remember,
these are ones whose names end in 'A' or 'B', rather than 'Z':
-
~~~
$ cd north-pacific-gyre/2012-07-03
$ for datafile in *[AB].txt
@@ -293,8 +279,7 @@ $ for datafile in *[AB].txt
> echo $datafile
> done
~~~
-
-
+{:class="in"}
~~~
NENE01729A.txt
NENE01729B.txt
@@ -303,22 +288,20 @@ NENE01736A.txt
NENE02043A.txt
NENE02043B.txt
~~~
-
+{:class="out"}
Her next step is to decide
what to call the files that the `goostats` analysis program will create.
Prefixing each input file's name with "stats" seems simple,
so she modifies her loop to do that:
-
~~~
$ for datafile in *[AB].txt
> do
> echo $datafile stats-$datafile
> done
~~~
-
-
+{:class="in"}
~~~
NENE01729A.txt stats-NENE01729A.txt
NENE01729B.txt stats-NENE01729B.txt
@@ -327,7 +310,7 @@ NENE01736A.txt stats-NENE01736A.txt
NENE02043A.txt stats-NENE02043A.txt
NENE02043B.txt stats-NENE02043B.txt
~~~
-
+{:class="out"}
She hasn't actually run `goostats` yet,
but now she's sure she can select the right files and generate the right output filenames.
@@ -341,20 +324,18 @@ In response,
the shell redisplays the whole loop on one line
(using semi-colons to separate the pieces):
-
~~~
$ for datafile in *[AB].txt; do echo $datafile stats-$datafile; done
~~~
-
+{:class="in"}
Using the left arrow key,
Nelle backs up and changes the command `echo` to `goostats`:
-
~~~
$ for datafile in *[AB].txt; do bash goostats $datafile stats-$datafile; done
~~~
-
+{:class="in"}
When she presses enter,
the shell runs the modified command.
@@ -365,11 +346,10 @@ She kills the job by typing Control-C,
uses up-arrow to repeat the command,
and edits it to read:
-
~~~
$ for datafile in *[AB].txt; do echo $datafile; bash goostats $datafile stats-$datafile; done
~~~
-
+{:class="in"}
> #### Beginning and End
>
@@ -380,14 +360,13 @@ $ for datafile in *[AB].txt; do echo $datafile; bash goostats $datafile stats-$d
When she runs her program now,
it produces one line of output every five seconds or so:
-
~~~
NENE01729A.txt
NENE01729B.txt
NENE01736A.txt
...
~~~
-
+{:class="out"}
1518 times 5 seconds,
divided by 60,
diff --git a/novice/shell/05-script.md b/novice/shell/05-script.md
index 723d45d21..799e6022c 100644
--- a/novice/shell/05-script.md
+++ b/novice/shell/05-script.md
@@ -38,12 +38,10 @@ Once we have saved the file,
we can ask the shell to execute the commands it contains.
Our shell is called `bash`, so we run the following command:
-
~~~
$ bash middle.sh
~~~
-
-
+{:class="in"}
~~~
ATOM 14 C 1 -1.463 -0.666 1.001 1.00 0.00
ATOM 15 C 1 0.762 -0.929 0.295 1.00 0.00
@@ -51,7 +49,7 @@ ATOM 16 C 1 0.771 -0.937 1.840 1.00 0.00
ATOM 17 C 1 -0.664 -0.610 2.293 1.00 0.00
ATOM 18 C 1 -4.705 2.108 -0.396 1.00 0.00
~~~
-
+{:class="out"}
Sure enough,
our script's output is exactly what we would get if we ran that pipeline directly.
@@ -74,27 +72,23 @@ but that would probably take longer than just retyping the command.
Instead,
let's edit `middle.sh` and replace `cholesterol.pdb` with a special variable called `$1`:
-
~~~
$ cat middle.sh
~~~
-
-
+{:class="in"}
~~~
head -20 $1 | tail -5
~~~
-
+{:class="out"}
Inside a shell script,
`$1` means "the first filename (or other parameter) on the command line".
We can now run our script like this:
-
~~~
$ bash middle.sh cholesterol.pdb
~~~
-
-
+{:class="in"}
~~~
ATOM 14 C 1 -1.463 -0.666 1.001 1.00 0.00
ATOM 15 C 1 0.762 -0.929 0.295 1.00 0.00
@@ -102,16 +96,14 @@ ATOM 16 C 1 0.771 -0.937 1.840 1.00 0.00
ATOM 17 C 1 -0.664 -0.610 2.293 1.00 0.00
ATOM 18 C 1 -4.705 2.108 -0.396 1.00 0.00
~~~
-
+{:class="out"}
or on a different file like this:
-
~~~
$ bash middle.sh vitamin-a.pdb
~~~
-
-
+{:class="in"}
~~~
ATOM 14 C 1 1.788 -0.987 -0.861
ATOM 15 C 1 2.994 -0.265 -0.829
@@ -119,28 +111,24 @@ ATOM 16 C 1 4.237 -0.901 -1.024
ATOM 17 C 1 5.406 -0.117 -1.087
ATOM 18 C 1 -0.696 -2.628 -0.641
~~~
-
+{:class="out"}
We still need to edit `middle.sh` each time we want to adjust the range of lines,
though.
Let's fix that by using the special variables `$2` and `$3`:
-
~~~
$ cat middle.sh
~~~
-
-
+{:class="in"}
~~~
head $2 $1 | tail $3
~~~
-
-
+{:class="out"}
~~~
$ bash middle.sh vitamin-a.pdb -20 -5
~~~
-
-
+{:class="in"}
~~~
ATOM 14 C 1 1.788 -0.987 -0.861
ATOM 15 C 1 2.994 -0.265 -0.829
@@ -148,24 +136,22 @@ ATOM 16 C 1 4.237 -0.901 -1.024
ATOM 17 C 1 5.406 -0.117 -1.087
ATOM 18 C 1 -0.696 -2.628 -0.641
~~~
-
+{:class="out"}
This works,
but it may take the next person who reads `middle.sh` a moment to figure out what it does.
We can improve our script by adding some [comments](../../gloss.html#comment) at the top:
-
~~~
$ cat middle.sh
~~~
-
-
+{:class="in"}
~~~
# Select lines from the middle of a file.
# Usage: middle.sh filename -end_line -num_lines
head $2 $1 | tail $3
~~~
-
+{:class="out"}
A comment starts with a `#` character and runs to the end of the line.
The computer ignores comments,
@@ -174,11 +160,10 @@ but they're invaluable for helping people understand and use scripts.
What if we want to process many files in a single pipeline?
For example, if we want to sort our `.pdb` files by length, we would type:
-
~~~
$ wc -l *.pdb | sort -n
~~~
-
+{:class="in"}
because `wc -l` lists the number of lines in the files
and `sort -n` sorts things numerically.
@@ -193,22 +178,18 @@ which means,
"All of the command-line parameters to the shell script."
Here's an example:
-
~~~
$ cat sorted.sh
~~~
-
-
+{:class="in"}
~~~
wc -l $* | sort -n
~~~
-
-
+{:class="out"}
~~~
$ bash sorted.sh *.dat backup/*.dat
~~~
-
-
+{:class="in"}
~~~
29 chloratin.dat
89 backup/chloratin.dat
@@ -217,7 +198,7 @@ $ bash sorted.sh *.dat backup/*.dat
172 backup/sphag-merged.dat
182 girmanis.dat
~~~
-
+{:class="out"}
> #### Why Isn't It Doing Anything?
>
@@ -273,11 +254,10 @@ Instead of typing them in again
(and potentially getting them wrong)
we can do this:
-
~~~
$ history | tail -4 > redo-figure-3.sh
~~~
-
+{:class="in"}
The file `redo-figure-3.sh` now contains:
@@ -350,19 +330,17 @@ done
She saves this in a file called `do-stats.sh`
so that she can now re-do the first stage of her analysis by typing:
-
~~~
$ bash do-stats.sh *[AB].txt
~~~
-
+{:class="in"}
She can also do this:
-
~~~
$ bash do-stats.sh *[AB].txt | wc -l
~~~
-
+{:class="in"}
so that the output is just the number of files processed
rather than the names of the files that were processed.
diff --git a/novice/shell/06-find.md b/novice/shell/06-find.md
index 506c9a920..2b317fb22 100644
--- a/novice/shell/06-find.md
+++ b/novice/shell/06-find.md
@@ -25,12 +25,10 @@ For our examples,
we will use a file that contains three haikus taken from a
1998 competition in *Salon* magazine:
-
~~~
$ cat haiku.txt
~~~
-
-
+{:class="in"}
~~~
The Tao that is seen
Is not the true Tao, until
@@ -44,7 +42,7 @@ Yesterday it worked
Today it is not working
Software is like that.
~~~
-
+{:class="out"}
> #### Forever, or Five Years
>
@@ -54,18 +52,16 @@ Software is like that.
Let's find lines that contain the word "not":
-
~~~
$ grep not haiku.txt
~~~
-
-
+{:class="in"}
~~~
Is not the true Tao, until
"My Thesis" not found
Today it is not working
~~~
-
+{:class="out"}
Here, `not` is the pattern we're searching for.
It's pretty simple:
@@ -75,17 +71,15 @@ The output is the three lines in the file that contain the letters "not".
Let's try a different pattern: "day".
-
~~~
$ grep day haiku.txt
~~~
-
-
+{:class="in"}
~~~
Yesterday it worked
Today it is not working
~~~
-
+{:class="out"}
This time,
the output is lines containing the words "Yesterday" and "Today",
@@ -94,28 +88,25 @@ If we give `grep` the `-w` flag,
it restricts matches to word boundaries,
so that only lines with the word "day" will be printed:
-
~~~
$ grep -w day haiku.txt
~~~
-
+{:class="in"}
In this case, there aren't any, so `grep`'s output is empty.
Another useful option is `-n`, which numbers the lines that match:
-
~~~
$ grep -n it haiku.txt
~~~
-
-
+{:class="in"}
~~~
5:With searching comes loss
9:Yesterday it worked
10:Today it is not working
~~~
-
+{:class="out"}
Here, we can see that lines 5, 9, and 10 contain the letters "it".
@@ -125,12 +116,10 @@ since `-i` makes matching case-insensitive and `-v` inverts the match,
using them both only prints lines that *don't* match the pattern
in any mix of upper and lower case:
-
~~~
$ grep -i -v the haiku.txt
~~~
-
-
+{:class="in"}
~~~
You bring fresh toner.
@@ -140,7 +129,7 @@ Yesterday it worked
Today it is not working
Software is like that.
~~~
-
+{:class="out"}
`grep` has lots of other options.
To find out what they are, we can type `man grep`.
@@ -148,12 +137,10 @@ To find out what they are, we can type `man grep`.
it prints a description of a command and its options,
and (if you're lucky) provides a few examples of how to use it:
-
~~~
$ man grep
~~~
-
-
+{:class="in"}
~~~
GREP(1) GREP(1)
@@ -189,7 +176,7 @@ Interpret PATTERN as a list of fixed strings, separated by newlines, any of whi
matched. (-F is specified by POSIX.)
... ... ...
~~~
-
+{:class="out"}
> #### Wildcards
>
@@ -238,12 +225,10 @@ Sure enough,
`find`'s output is the names of the five directories in our little tree
(including `.`):
-
~~~
$ find . -type d -print
~~~
-
-
+{:class="in"}
~~~
./
./data
@@ -251,17 +236,15 @@ $ find . -type d -print
./tools
./tools/old
~~~
-
+{:class="out"}
If we change `-type d` to `-type f`,
we get a listing of all the files instead:
-
~~~
$ find . -type f -print
~~~
-
-
+{:class="in"}
~~~
./data/one.txt
./data/two.txt
@@ -269,7 +252,7 @@ $ find . -type f -print
./tools/format
./tools/stats
~~~
-
+{:class="out"}
`find` automatically goes into subdirectories,
their subdirectories,
@@ -277,62 +260,54 @@ and so on to find everything that matches the pattern we've given it.
If we don't want it to,
we can use `-maxdepth` to restrict the depth of search:
-
~~~
$ find . -maxdepth 1 -type f -print
~~~
-
-
+{:class="in"}
~~~
./notes.txt
~~~
-
+{:class="out"}
The opposite of `-maxdepth` is `-mindepth`,
which tells `find` to only report things that are at or below a certain depth.
`-mindepth 2` therefore finds all the files that are two or more levels below us:
-
~~~
$ find . -mindepth 2 -type f -print
~~~
-
-
+{:class="in"}
~~~
./data/one.txt
./data/two.txt
./tools/format
./tools/stats
~~~
-
+{:class="out"}
Another option is `-empty`,
which restricts matches to empty files and directories:
-
~~~
$ find . -empty -print
~~~
-
-
+{:class="in"}
~~~
./thesis
./tools/old
~~~
-
+{:class="out"}
Now let's try matching by name:
-
~~~
$ find . -name *.txt -print
~~~
-
-
+{:class="in"}
~~~
./notes.txt
~~~
-
+{:class="out"}
We expected it to find all the text files,
but it only prints out `./notes.txt`.
@@ -340,11 +315,10 @@ The problem is that the shell expands wildcard characters like `*` *before* comm
Since `*.txt` in the current directory expands to `notes.txt`,
the command we actually ran was:
-
~~~
$ find . -name notes.txt -print
~~~
-
+{:class="in"}
`find` did what we asked; we just asked for the wrong thing.
@@ -354,18 +328,16 @@ put `*.txt` in single quotes to prevent the shell from expanding the `*` wildcar
This way,
`find` actually gets the pattern `*.txt`, not the expanded filename `notes.txt`:
-
~~~
$ find . -name '*.txt' -print
~~~
-
-
+{:class="in"}
~~~
./data/one.txt
./data/two.txt
./notes.txt
~~~
-
+{:class="out"}
> #### Listing vs. Finding
>
@@ -384,19 +356,17 @@ How can we combine that with `wc -l` to count the lines in all those files?
The simplest way is to put the `find` command inside `$()`:
-
~~~
$ wc -l $(find . -name '*.txt' -print)
~~~
-
-
+{:class="in"}
~~~
70 ./data/one.txt
420 ./data/two.txt
30 ./notes.txt
520 total
~~~
-
+{:class="out"}
When the shell executes this command,
the first thing it does is run whatever is inside the `$()`.
@@ -404,11 +374,10 @@ It then replaces the `$()` expression with that command's output.
Since the output of `find` is the three filenames `./data/one.txt`, `./data/two.txt`, and `./notes.txt`,
the shell constructs the command:
-
~~~
$ wc -l ./data/one.txt ./data/two.txt ./notes.txt
~~~
-
+{:class="in"}
which is what we wanted.
This expansion is exactly what the shell does when it expands wildcards like `*` and `?`,
@@ -420,16 +389,14 @@ the second looks for lines inside those files that match another pattern.
Here, for example, we can find PDB files that contain iron atoms
by looking for the string "FE" in all the `.pdb` files below the current directory:
-
~~~
$ grep FE $(find . -name '*.pdb' -print)
~~~
-
-
+{:class="in"}
~~~
./human/heme.pdb:ATOM 25 FE 1 -0.924 0.535 -0.518
~~~
-
+{:class="out"}
> #### Binary Files
>
diff --git a/novice/teaching/02-shell.md b/novice/teaching/02-shell.md
index a8faefb2b..2158ff6e1 100644
--- a/novice/teaching/02-shell.md
+++ b/novice/teaching/02-shell.md
@@ -117,12 +117,11 @@ as long as learners using Windows do not run into roadblocks such as:
* On Windows, it appears that:
-
~~~
$ cd
$ cd Desktop
~~~
-
+ {:class="in"}
will always put someone on their desktop.
Have them create the example directory for the shell exercises there