Monday, January 31, 2011

Unix spoken here (3)

Let's do some more with Unix commands. Previous posts here and here.

You might have noticed that I have a very short prompt in Terminal, just the character `>` followed by a space. That's because I have an (invisible) file in my home directory named .bash_profile, containing this line:

> cat ~/.bash_profile
PS1="> "; export PS1

We can change back to the original behavior by changing the name of the file or moving it, and then re-starting Terminal:

mv ~/.bash_profile ~/Desktop/x.txt

c-98-236-78-154:Desktop telliott$

We could comment out that line of the file (now that it's visible with no leading `.` in the filename, we can easily open it in TextEdit).

#PS1="> ";  export PS1

But I like it, so I'll revert to the original situation.

I think there is a way to get TextEdit to show hidden files in the Open dialog, but I forget how at the moment. In any event, it's interesting that having opened and closed the file while it was visible on the Desktop, Open Recent now shows .bash_profile as an option.

Another way to edit the file is to use pico (a command line editor):

> pico ~/.bash_profile

I'm sure you can figure out how to use pico.

One more useful thing in .bash_profile is modification to the $PATH variable. Let's look at that from the command line:

> echo $PATH

When I call ls, for example, these directories are searched in turn until the program is discovered finally. It is in:

> whereis ls

If I wanted to modify the $PATH variable I could do:

> PATH=~/Desktop:$PATH;  export PATH
> echo $PATH

My $PATH is pretty complicated for several reasons: use of MacPorts, some things related to ncbi and X11, etc. It would take too long to explain.

The shell has command history. If you want to repeat a command, just press the up arrow key. To repeat a command further back, keep pushing until you see the one you want. Then press Return. Suppose you have a series of commands (say 3 in a row), and the first of these is 6 commands ago. Press the arrow 6 times, then return. Press the arrow 6 times, then return. Press the arrow 6 times, then return. Because the command history is updated each time, 6 arrow presses gets you back exactly where you need to be for each of the three commands in the sequence.

Alternatively you could do history:

> history
501 cd Desktop
502 pico ~/bash_profile
503 echo $PATH
504 file ls
505 whereis ls
506 PATH=~/Desktop:$PATH; export $PATH
507 PATH=~/Desktop:$PATH; export PATH
508 echo $PATH
509 history

which lists each command I've entered since the last time I booted my machine (even saves between Terminal sessions). One can select a command from the history by number or by partial name match:

> !505
whereis ls
> !wh
whereis ls

First it prints the command, and then the result. You can combine commands on a single line with `;`

> !504; !512
whereis ls; echo abc
> history | tail -2
515 whereis ls; echo abc
516 history
> !515
whereis ls; echo abc

We're getting pretty good with this stuff! We don't really want to list all 500+ commands in the history, just the last two. So we feed the results of history to the Unix tool called tail through a `|`, a Unix "pipe." tail takes an option for how many lines at the end of the "file" to display.

The Unix command grep searches lines of text for those matching a pattern. It's particularly useful in combination with `|`.

> history | grep pico
40 pico ~/.hgrc
298 pico
502 pico ~/bash_profile
515 history | grep pico

Here, I edited some file with pico but I can't remember which one it was. So the entire output of the history is fed through the pipe to grep, searching for lines containing the pattern. Now I can just do:

> !40
pico ~/.hgrc

I won't show you the file.

The last command for this post is ln with the option -s which makes a "soft link" to a file. I can never remember, but you want to put the existing file first (that's the opposite of the way I would design it):

> cat temp/y.txt
echo "abc"
> ln -s foo temp/y.txt
ln: temp/y.txt: File exists
> ln -s temp/y.txt foo
> ls
foo temp
> cat foo
echo "abc"
> ls -l
total 8
lrwxr-xr-x 1 telliott staff 10 Jan 31 07:53 foo -> temp/y.txt
drwxr-xr-x 5 telliott staff 170 Jan 31 07:53 temp

Now the listing for foo shows an `l` as the first character in the file mode, and it also shows -> temp/y.txt, where it links to.