Rixstep
 About | ACP | Buy | Industry Watch | Learning Curve | News | Products | Search | Substack
Home » Learning Curve

ls(c)d

Time for some mind-blowing experiments.


Get It

Try It

A bit of philosophy and a bit of learning. Work work work, learn learn learn. For Unix n00bs only.

This little snippet will look at two obsequious Unix commands: ls and cd (and in that order). We hope you enjoy the ride. We start with ls.

ls

A wise guru once said that if you understand ls, you understand Unix. He was wise.

But the man page for ls is intimidating. It starts like this:

SYNOPSIS
     ls [-ACFLRSTWacdfgiklnoqrstux1] [file ...]

Obviously that's no way to climb a learning curve. It might be interesting if you've made it through the forest and out the other end, but the risk is great it will scare you off, and that can't ever be good. So we're going to start slowly.

ls stands for list. Things were cryptic back in the early days of Unix, and for two reasons:

  1. They used teletype machines back in those old days and typing and paper were at a premium.
  2. Ken Thompson, main creator of Unix, is cryptic like few others. He told his own mother to rename him 'K' (not true - but he was cryptic - bless him).

When Dennis Ritchie finished the C language and told Ken he was thinking of calling his new language the 'New B' after Ken's language 'B' on which it was based (which in turn was based on 'BCPL' but that name was waaay too long for Ken), Ken told Dennis 'no'. The name was too long. Waaay too long. Dennis then suggested 'NB' which stands for 'New B' and again Ken told Dennis the name was waaay too long. (And this is very true.)

So Ken is cryptic. And ls stands for list.

ls lists the contents of a directory. It can be made to list the contents of any directory anywhere, but we're going to use it in its simpler fashion, to always list the directory we're actually in (our current working directory).

So the easiest implementation of ls is to just type ls, hit <Enter>, and hope for the best.

% ls
Applications Network      Volumes      cores        mach         private      usr
Developer    System       automount    dev          mach.sym     sbin         var
Library      Users        bin          etc          mach_kernel  tmp

That's actually a listing of the root directory, but whatever: that's the way it comes out, and it doesn't tell us a whole lot. We get names and no more. We don't know if we have directories, or files, or exactly what we have. So let's increment.

% ls -l
total 8745
drwxrwxr-x  18 root  admin      612 May 19 20:39 Applications
drwxrwxr-x  11 root  admin      374 May 19 20:21 Developer
drwxrwxr-x  26 root  admin      884 May 19 20:49 Library
drwxr-xr-x   6 root  wheel      204 May 19 19:57 Network
drwxr-xr-x   3 root  wheel      102 May 19 20:21 System
drwxrwxr-t   4 root  admin      136 Jun 30 20:00 Users
drwxrwxrwt   2 root  wheel       68 Jul  3 09:50 Volumes
dr-xr-xr-x   1 root  wheel      512 Jul  4 14:58 automount
drwxr-xr-x  35 root  wheel     1190 May 20  2003 bin
drwxrwxrwt   2 root  wheel       68 Jan 15  2003 cores
dr-xr-xr-x   2 root  wheel      512 Jul  4 14:32 dev
lrwxrwxr-t   1 root  staff       11 Jul  4 14:32 etc -> private/etc
lrwxrwxr-t   1 root  staff        9 Jul  4 14:32 mach -> /mach.sym
-r--r--r--   1 root  staff   709440 Jul  4 14:32 mach.sym
-rw-r--r--   1 root  wheel  3744576 Aug 13  2003 mach_kernel
drwxr-xr-x   6 root  wheel      204 Jul  4 14:32 private
drwxr-xr-x  60 root  wheel     2040 Aug 11  2003 sbin
lrwxrwxr-t   1 root  staff       11 Jul  4 14:32 tmp -> private/tmp
drwxr-xr-x  10 root  wheel      340 May 19 20:21 usr
lrwxrwxr-t   1 root  staff       11 Jul  4 14:32 var -> private/var

This is the so-called 'long' listing (which is what the switch 'l' stands for). Now we have a lot more information.

The 'total' at the top is the 'block usage' for what we've listed - a block is a number of disk sectors.

Now, starting from the left, we find columns which tell us the following:

  • the protection mode and file type
  • the number of links
  • the file's owner
  • the owner's group
  • the file size
  • the date and time last modified
  • the file name

ls doesn't get any of this information in the actual directory. To get the information, ls has to scoot to what is known as the volume's ilist. This is comparable in location and in relevance to the HFS catalog file - but not at all in how it works. All Unix directories have are file names and so-called inodes which index into the ilist. It's in the ilist that all of the information is found.

But that's OK because it's only one 'scoot' on disk. And straight to it, because it already knows the offset in the ilist - the inode index (woohoo).

Protection Mode, File Type

The first letter in this first column denotes a file type. 'd' stands for directory, 'l' stands for 'symbolic link', and '-' means it's neither - just an ordinary file.

Next we have three groupings of rwx - or a lack thereof. The r stands for read access, the w for write access, and the x for eXecute access. So files can be marked so you can read them but not write to them, or write to them but not read them, and anything that is 'run' - executed - must have an x or otherwise the system will pretend the file is not there.

There's also a t in that first column for certain files - we'll come back to that later. It's a 'sticky bit'. Another character which shows up now and again is the s - we'll come back to that too - it stands for set ID (just hold onto that).

There are three groupings of rwx above, and in left to right order they're for the access rights of the file's owner, the owner's group, and everybody else. Who the file's owner is can be seen in another column, as can the owner's group.

The file size, the last modified stamp, and the file name should be self-explanatory.

So now we've listed everything in the root directory? Not quite. Unix normally 'hides' files that have a name beginning with a dot ('.'). But this is only a convenience - you can list them too by simply adding the 'a' ('all') switch.

% ls -al
total 8753
drwxrwxr-t  26 root  staff        884 Jul  4 14:32 .
drwxrwxr-t  26 root  staff        884 Jul  4 14:32 ..
d-wx-wx-wx   2 root  unknown       68 May 19 19:43 .Trashes
-r--r--r--   1 root  wheel        156 Jan 15  2003 .hidden
dr--r--r--   2 root  wheel         96 Jul  4 14:32 .vol
drwxrwxr-x  18 root  admin        612 May 19 20:39 Applications
drwxrwxr-x  11 root  admin        374 May 19 20:21 Developer
drwxrwxr-x  26 root  admin        884 May 19 20:49 Library
drwxr-xr-x   6 root  wheel        204 May 19 19:57 Network
drwxr-xr-x   3 root  wheel        102 May 19 20:21 System
drwxrwxr-t   4 root  admin        136 Jun 30 20:00 Users
drwxrwxrwt   2 root  wheel         68 Jul  3 09:50 Volumes
dr-xr-xr-x   1 root  wheel        512 Jul  4 15:08 automount
drwxr-xr-x  35 root  wheel       1190 May 20  2003 bin
drwxrwxrwt   2 root  wheel         68 Jan 15  2003 cores
dr-xr-xr-x   2 root  wheel        512 Jul  4 14:32 dev
lrwxrwxr-t   1 root  staff         11 Jul  4 14:32 etc -> private/etc
lrwxrwxr-t   1 root  staff          9 Jul  4 14:32 mach -> /mach.sym
-r--r--r--   1 root  staff     709440 Jul  4 14:32 mach.sym
-rw-r--r--   1 root  wheel    3744576 Aug 13  2003 mach_kernel
drwxr-xr-x   6 root  wheel        204 Jul  4 14:32 private
drwxr-xr-x  60 root  wheel       2040 Aug 11  2003 sbin
lrwxrwxr-t   1 root  staff         11 Jul  4 14:32 tmp -> private/tmp
drwxr-xr-x  10 root  wheel        340 May 19 20:21 usr
lrwxrwxr-t   1 root  staff         11 Jul  4 14:32 var -> private/var

Several new files now appear. We find '.Trashes', '.hidden', and '.vol'. We also find the cryptic '.' and '..'.

'.' is a synonym for 'this directory'. It is a real directory entry, but it just points to wherever we already are. '..' points to the parent directory. These two entries are not trivial, but are a great help to the system when we navigate about.

Say you want to go up to your parent directory from where you currently are. How will the system find that directory? Simple: it looks for the '..' entry.

Which is why '.' is also listed: anytime you create a subdirectory, your system takes the value at '.' and puts it in your subdirectory as '..' - that way you can navigate down and back again. Pretty ingenious, eh?

And still we haven't seen everything yet. The next switch is 'i' - which stands for inode.

% ls -ail
total 8753
     2 drwxrwxr-t  26 root  staff        884 Jul  4 14:32 .
     2 drwxrwxr-t  26 root  staff        884 Jul  4 14:32 ..
    17 d-wx-wx-wx   2 root  unknown       68 May 19 19:43 .Trashes
  7244 -r--r--r--   1 root  wheel        156 Jan 15  2003 .hidden
     0 dr--r--r--   2 root  wheel         96 Jul  4 14:32 .vol
   452 drwxrwxr-x  18 root  admin        612 May 19 20:39 Applications
 34931 drwxrwxr-x  11 root  admin        374 May 19 20:21 Developer
  1806 drwxrwxr-x  26 root  admin        884 May 19 20:49 Library
  7249 drwxr-xr-x   6 root  wheel        204 May 19 19:57 Network
  1825 drwxr-xr-x   3 root  wheel        102 May 19 20:21 System
  7259 drwxrwxr-t   4 root  admin        136 Jun 30 20:00 Users
  6846 drwxrwxrwt   2 root  wheel         68 Jul  3 09:50 Volumes
     6 dr-xr-xr-x   1 root  wheel        512 Jul  4 15:12 automount
  6847 drwxr-xr-x  35 root  wheel       1190 May 20  2003 bin
  7245 drwxrwxrwt   2 root  wheel         68 Jan 15  2003 cores
     2 dr-xr-xr-x   2 root  wheel        512 Jul  4 14:32 dev
 27441 lrwxrwxr-t   1 root  staff         11 Jul  4 14:32 etc -> private/etc
711778 lrwxrwxr-t   1 root  staff          9 Jul  4 14:32 mach -> /mach.sym
711777 -r--r--r--   1 root  staff     709440 Jul  4 14:32 mach.sym
  6887 -rw-r--r--   1 root  wheel    3744576 Aug 13  2003 mach_kernel
    19 drwxr-xr-x   6 root  wheel        204 Jul  4 14:32 private
  6980 drwxr-xr-x  60 root  wheel       2040 Aug 11  2003 sbin
 27503 lrwxrwxr-t   1 root  staff         11 Jul  4 14:32 tmp -> private/tmp
  7043 drwxr-xr-x  10 root  wheel        340 May 19 20:21 usr
 27526 lrwxrwxr-t   1 root  staff         11 Jul  4 14:32 var -> private/var

There is now a new leftmost column; otherwise the output is the same. This new column gives the inode of each file.

Again, what is the inode? The inode is the actual index in the volume ilist, a type of control block. And at this index in the ilist all file information can be found.

And what type of file information can be found? Exactly what you're looking at in the listing above.

There is more information in the iblock, but we've already seen most of it. A little bit more can be seen by adding the 'o' flag to the command line. What 'o' stands for is anyone's guess, but it means 'show special access flags' - something relatively new in the world of Unix.

% ls -ailo
total 8753
     2 drwxrwxr-t  26 root  staff    -     884 Jul  4 14:32 .
     2 drwxrwxr-t  26 root  staff    -     884 Jul  4 14:32 ..
    17 d-wx-wx-wx   2 root  unknown  -      68 May 19 19:43 .Trashes
  7244 -r--r--r--   1 root  wheel    -     156 Jan 15  2003 .hidden
     0 dr--r--r--   2 root  wheel    -      96 Jul  4 14:32 .vol
   452 drwxrwxr-x  18 root  admin    -     612 May 19 20:39 Applications
 34931 drwxrwxr-x  11 root  admin    -     374 May 19 20:21 Developer
  1806 drwxrwxr-x  26 root  admin    -     884 May 19 20:49 Library
  7249 drwxr-xr-x   6 root  wheel    -     204 May 19 19:57 Network
  1825 drwxr-xr-x   3 root  wheel    -     102 May 19 20:21 System
  7259 drwxrwxr-t   4 root  admin    -     136 Jun 30 20:00 Users
  6846 drwxrwxrwt   2 root  wheel    -      68 Jul  3 09:50 Volumes
     6 dr-xr-xr-x   1 root  wheel    -     512 Jul  4 15:15 automount
  6847 drwxr-xr-x  35 root  wheel    -    1190 May 20  2003 bin
  7245 drwxrwxrwt   2 root  wheel    -      68 Jan 15  2003 cores
     2 dr-xr-xr-x   2 root  wheel    -     512 Jul  4 14:32 dev
 27441 lrwxrwxr-t   1 root  staff    -      11 Jul  4 14:32 etc -> private/etc
711778 lrwxrwxr-t   1 root  staff    -       9 Jul  4 14:32 mach -> /mach.sym
711777 -r--r--r--   1 root  staff    -  709440 Jul  4 14:32 mach.sym
  6887 -rw-r--r--   1 root  wheel    - 3744576 Aug 13  2003 mach_kernel
    19 drwxr-xr-x   6 root  wheel    -     204 Jul  4 14:32 private
  6980 drwxr-xr-x  60 root  wheel    -    2040 Aug 11  2003 sbin
 27503 lrwxrwxr-t   1 root  staff    -      11 Jul  4 14:32 tmp -> private/tmp
  7043 drwxr-xr-x  10 root  wheel    -     340 May 19 20:21 usr
 27526 lrwxrwxr-t   1 root  staff    -      11 Jul  4 14:32 var -> private/var

There's a new column between the group name and the file size: in the above listing it's all dashes ('-'), meaning there are no special access flags, which is just as well - they're pretty tricky and can easily get you into trouble if you don't know how to use them.

Finally, the '->' in the rightmost column refers to a symbolic link target. For example, there's a directory called 'etc', but if you want to go into that directory, the listing tells you that you'll end up at '/private/etc' instead. The same goes for 'tmp' and 'var' in the listing above.

% cd etc
% pwd
/private/etc

See?

cd

Now that you've hopefully looked a bit at the ls command, it's time to look a bit at the Unix file system - and it doesn't matter if you're running HFS: OS X is a true Unix (FreeBSD) and HFS is supposed to behave like a Unix file system, according to a standard known as POSIX (Portable Operating System Interface) - so this applies anyway.

Colons Are Out

If you're a legacy Mac user, get this and get it well: colons are out. Colons were used since time immemorial with MacOS as a component separator, but to regurgitate the Pogueman for the umpteenth time: OS X is NOT MacOS. So get it out of your heads.

Carbon utilities can still use the colons, but they're an anomaly, and Carbon was only a concession to vendors with legacy Mac code. It's not the same thing, and it won't be around forever. Even with HFS running under the bonnet, OS X is Unix and nothing else, and in Unix the component separator is not the colon.

It's the slash.

/. [<-- a slash.]

Single Hierarchy

A Unix file system has a single hierarchy, and at the top of this single hierarchy is a directory known as root or the root directory, and it is denoted by the slash ('/') character. Most Unix file systems consist of several volumes; a typical OS X computer is no exception; but at the top - at the root - is the root directory, and this is where you find your bootable operating system - and the information about all the other volumes that have to be mounted as the startup proceeds.

[Mounting is the process whereby a new physical drive (or volume) gets logically connected to the existing file system so that a node in the existing file system (a 'path') becomes the place where the root of the new system is located. The system itself sees that the user experience is transparent - you normally won't notice a thing, but you'll still have multiple drives under one hierarchy. Even your inserted CDs and DVDs fall under this hierarchy - under /Volumes.]

The slash denotes the root directory, but it's also the component separator. A typical path such as:

/foo/bar/fubar.html

Means:

'In the root directory there is a subdirectory named 'foo'; in 'foo' there is another subdirectory named 'bar'; in 'bar' there is a file named 'fubar.html'.

Naturally all the components save possibly the last have to be directories.

Even the earliest Unix systems had multiple physical drives; the system would start with root ('/') already mounted; as the boot process continued, '/usr' would be mounted as well from the root directory of a secondary drive. Moving to '/usr' would in effect keep you in the same hierarchy, but actually move you to a new physical uniit. '/usr' was also where all user files were originally located. The file system would see that the transition from the boot drive to '/usr' and back again was seamless and transparent.

[You still have /usr on your OS X disks; it's just that it's hidden in the Finder and user files are located under /Users instead. But /usr is where all your compiler files are located, and where all your man pages are located, and all told there are over 10,000 there - perhaps unbeknownst to you?]

Working With cd

cd stands for 'change directory'. It's a short form of the original command name 'chdir'. You use cd to change directories. Wherever you go, you're followed by the concept of a working directory - a sort of shorthand the system keeps tabs on to remember where you are so it can understand abbreviated commands from you.

We start by opening a Terminal window and going to root.

% cd /

And now we ask the system to tell us our working directory.

% pwd
/

pwd stands for 'print working directory', and when this command first came out, it really printed, as there were no monitor screens (everything went on teletype).

So we're in root. Let's pull something out of the bag from the article on ls.

% ls -adil .
2 drwxrwxr-t  26 root  staff  884 Jul  4 14:32 .
% ls -adil ..
2 drwxrwxr-t  26 root  staff  884 Jul  4 14:32 ..

[We use the flag 'd' because we want to list these directories, not enumerate them.]

Note the inode in the leftmost column: they're the same. What this is saying (hold your breath) is that the parent directory of root is root itself.

Which, by the way, is a strict Unix definition: the parent directory of root is root itself.

cd takes command line arguments. We can specify what directory we want to change to. If follows very logically that inputting:

cd .

Will leave us exactly where we were, as '.' denotes 'here', 'this directory', our current working directory, but when we're in root, typing in:

cd ..

Will produce the same results! Try it:

% cd ..
% pwd
/

Relative Paths

A great thing about Unix is how it can handle relative paths. Absolute paths always begin with root - in other words, with a slash. Relative paths are relative to where we currently are - relative to our current working directory.

OK, so follow along here:

  1. If the parent directory of root is root itself, then root must be found in its parent; and

  2. If the slash is the component separator, then we must be able to make the wildest possible paths and still end up back where we started from!

OK, try it!

% cd ../../../../../././././.
% pwd
/

Or try this:

% cd /
% pwd
/
% cd Users/../Users/../Users/../Users/../Users/..
% pwd
/

Ah, the power of Unix...

Another handy tidbit is 'cd' with no command line arguments at all. This will always take you to your home directory. Every account has a home directory on Unix. It's established by your account information. When you log in, that's where you're placed, even if you don't see it. Try it now - you should end up in your special subdirectory to /Users.

% cd
% pwd
/Users/<YOU>

You can play further games if you want by separating your commands with semicolons instead of issuing them one at a time, and you can end up with something like this:

% cd /;cd;cd /;cd;cd /;cd;cd /;cd;cd /;cd
% pwd
/Users/<YOU>

You can go up to /Users in two ways - either by absolute path:

% cd /Users
% pwd
/Users

Or by relative path:

% cd
% pwd
/Users/<YOU>
% cd ..
% pwd
/Users

Finding Files

So how does the system go about finding /foo/bar/fubar.html?

Easy - or not, depending how you look at it:

  1. Go to / (root).
  2. Locate foo in / (root).
  3. Go to foo.
  4. Locate bar in foo.
  5. Go to bar.
  6. Locate fubar.html in bar.
  7. Do whatever you want with fubar.html, because now you've found it.

That's it. It seems like a lot, but it's not really. And yet this is what the file system has to do for every file you want to access.

Otherwise, cd is that straightforward: give it either an absolute path or a relative path from where you are and you go there.

[Note: don't bother looking up cd's man page - you'll most likely end up in a forest of documentation for your current shell and never be able to find anything anyway. cd changes directories - that's all you need. It probably doesn't exist as a standalone program file anymore anyway.]

About | ACP | Buy | Industry Watch | Learning Curve | News | Products | Search | Substack
Copyright © Rixstep. All rights reserved.