The cut command

The cut command has the ability to cut out characters or fields. cut uses delimiters.

The cut command uses delimiters to determine where to split fields, so the first thing we need to understand about cut is how it determines what its delimiters are. By default, cut's delimiters are stored in a shell variable called IFS (Input Field Separators).

Typing:

set | grep IFS
            

will show you what the separator characters currently are; at present, IFS is either a tab, or a new line or a space.

Looking at the output of our free command, we successfully separated every field by a space (remember the tr command!)

Similarly, if our delimiter between fields was a comma, we could set the delimiter within cut to be a comma using the -d switch:

cut -d ","
            

The cut command lets one cut on the number of characters or on the number of fields. Since we're only interested in fields 2,3 and 4 of our memory, we can extract these using:

free | tr -s ' ' | sed '/^Mem/!d' | cut -d" " -f2-4
            

Why do you need to set -d " " even when IFS already specifies that a spaces is a IFS ?

If this does not work on your system, then you need to set the IFS variable.

Detour:

Setting shell variables is easy. If you use the bash or the Bourne shell (sh), then:

IFS=" \t\n"
            

In the csh or the ksh, it would be:

	setenv IFS=" \t\n"
            

That ends this short detour.

At this point, it would be nice to save the output to a file. So let's append this to a file called mem.stats:

free | tr -s ' ' | sed '/^Mem/!d' | cut -d" " -f2-4 >> mem.stats
            

Every time you run this particular command it should append the output to the mem.stats file.

The -f switch allows us to cut based upon fields. If we were wanting to cut based upon characters (e.g. cut character 6-13 and 15, 17) we would use the -c switch.

To affect the above example:

free | tr -s ' ' | sed '/^Mem/!d' | cut -c6-13,15,17 >> mem.stats
            

First Example in stages:

1. For the next example I'd like you to make sure that you've logged on as a user (potentially root) on one of your virtual terminals.

How do you get to a virtual terminal? Ctrl-Alt plus F1 or F2 or F3 etcetera.

It should prompt you for a username and a password. Log in as root, or as yourself or as a different user and once you've logged in, switch back to your X terminal with Alt-F7. If you weren't working on X at the beginning of this session, then the Ctrl + Alt + F1 is not necessary. A simple Alt + F2 would open a new terminal, to return to the first terminal press Alt+F1.

2. Run the who command:

who 
                

This will tell us who is logged on to the system. We could also run the w command:

w
                

This will not only tell us who is logged on to our system, but what they're doing. Let's use the w command, since we want to save information about what users are doing on our system. We may also want to save information about how long they've been idle and what time they logged on.

3. Find out who is logged on to your system. Pipe the output of the w command into the input of cut. This time however we're not going to use a delimiter to delimit fields but we're going to cut on characters. We could say:

w |cut -c1-8
                

This tells the cut command the first eight characters. Doing this you will see that it cuts up until the first digit of the second. So in my case the time is now

09:57:24
                

and it cuts off to

09:57:2
                

It also cuts off the user. So if you look at this, you're left with USER and all the users currently logged onto your system. And that's cutting exactly 8 characters.

4. To cut characters 4 to 8?

w | cut -c4-8
                

This will produce slightly bizarre-looking output.

So cut cannot only cut fields, it can cut exact characters and ranges of characters. We can cut any number of characters in a line.

Second Example in stages:

Often cutting characters in a line is less than optimal, since you never know how long your usernames might be. Really long usernames would be truncated which clearly would not be acceptable. Cutting on characters is rarely a long-term solution.. It may work because your name is Sam, but not if your name is Jabberwocky!

1. Let's do a final example using cut. Using our password file:

cat /etc/passwd
                

I'd like to know all usernames on the system, and what shell each is using.

The password file has 7 fields separated by a ':'. The first field is the login username, the second is the password which is an x (because it is kept in the shadow password file), the third field is the userid, the fourth is the group id, the fifth field is the comment, the sixth field is the users home directory and the seventh field 7 indicates the shell that the user is using. I'm interested in fields 1 and 7.

2. How would we extract the particular fields? Simple:[6]

cat /etc/passwd |cut -d: -f1,7
                
cut -d  -f1,7	
or
cut -d" " -f 1,7
                

If we do this, we should end up with just the usernames and their shells. Isn't that a nifty trick?

3. Let's pipe that output to the sort command, to sort the usernames alphabetically:

cat /etc/passwd | cut -d: -f1,7 | sort
                

Third example in stages

So this is a fairly simple way to extract information out of files. The cut command doesn't only work with files, it also works with streams. We could do a listing which that would produce a number of fields. If you recall, we used the tr command earlier to squeeze spaces.

ls -al 
                

If you look at this output, you will see lines of fields. Below is a quick summary of these fields and what they refer to.

field number indication of
1 permissions of the file
2 number of links to the file
3 user id
4 group id
5 size of the file
6 month the file was modified
7 day the file was modified
8 time the file was modified
9 name of the file

I'm particularly interested in the size and the name of each file.

1. Let's try and use our cut command in the same way that we used it for the password file:

ls -al |cut -d' ' -f5,8
                

The output is not as expected. Because it is using a space to look for separate fields, and the output contains tabs. This presents us with a bit of a problem.

2. We could try using a \t (tab) for the delimiter instead of a space, however cut only accepts a single character (\t is two characters). An alternative way of inserting a special character like tab is to type Ctrl-v then hit the tab key.

^v + <tab>
                

That would replace the character by a tab.

ls -al | cut -d"       " -f5,8
                

That makes the delimiter a tab. But, we still don't get what we want, so let's try squeezing multiple spaces into a single space in this particular output. Thus:

ls -la |tr -s ' '|cut -d' ' -f5,8
                

3. And hopefully that should now produce the output we're after. If it produces the output we're after on your system, then we're ready for lift-off. If it doesn't, then try the command again.

Now what happens if we want to swap the name with the size? I'll leave that as an exercise for you.

Exercises:

  1. Using the tr and the cut commands, perform the following:

  2. Obtain the mount point, the percentage in use and the partition of that mount of you disk drive to produce the following:

    /dev/hdb2 80% /home
                            
  3. Replace the spaces in your output above by colons (:)

  4. Remove the /dev/shm line

  5. Keep all output from the running of this command for later use.

  6. As root, make the following change:[7]

    chmod o+r /dev/hda 
                            
  7. Now, obtain the Model and Serial Number of your hard disk, using the command hdparm.

  8. Obtain the stats (reads and writes etc.) on your drive using the iostat command, keeping the output as a comma separated value format file for later use



[6] I do not enclose the : in quotes, although this would also work. The reason for enclosing a space (or tab) in quotes is so that you and I could see it. What is more legible?

[7] obviously, if you do not have a hda, you will need to adjust the value to suite your needs!!