Mac OS X Command Line 101
by Richard Burton
Understanding Metacharacters
Part III of this series...
May 10th, 2002
"Well, I never metacharacter I didn't like."
- Ron Wurtz (a friend from grad school, you don't know him)
This series is designed to help you learn more about the Mac OS X command line. If you have any questions about what you read here, check out the earlier columns, write back in the comments below, or join us in Hardcore X! forum.
[Editor's Note: This installment was originally supposed to have been published as Part IV of this series, due to an error on TMO's part. It should be read after Part IV, The Missing Argument Chapter, which has been published early for those working along with the series.]
In the previous column, we looked at arguments and options, using the cd and ls commands to show commands requiring and responding to different numbers and types of arguments. While the ability to manipulate the commands with different arguments is handy, it only hinted at the power at your fingertips.
The Unix shells have a set of special characters known as 'metacharacters'. We have run into these before. In our first discussion, involving the tcsh prompt and the cd command, it was noted that the tilde character, '~', is a shorthand for 'my home directory'. What is really means is 'the home directory of the user following me'; however, if there is no user, it defaults to your home directory.
[localhost:~] dr_unix% pwd
/Users/dr_unix
[localhost:~] dr_unix% cd ~
[localhost:~] dr_unix% pwd
/Users/dr_unix
[localhost:~] dr_unix% cd ~root
[localhost:~root] dr_unix% pwd
/private/var/root
[localhost:~root] dr_unix% cd ~fred
Unknown user: fred.
[localhost:~root] dr_unix% cd ~
[localhost:~] dr_unix% pwd
/Users/dr_unix
[localhost:~] dr_unix%
Here, when we type cd ~, the '~' is expanded to our current home directory, /Users/dr_unix, before the command is passed to the system. The shell takes the cd ~root command, determines that the home directory for root is '/private/var/root', then passes the command cd /private/var/root to the system. Likewise, for the command cd ~fred, the shell cannot find a user 'fred' on the system, so it prints the error message (Unknown user: fred.) and does not change directory.
'~' is part of a special class of characters called 'filename metacharacters'. The shell interprets them differently than a regular old character (like, say, a 'b' or an 'N'). As we've seen, in the case of '~', the shell will expand these characters behind the scenes, in a way that depends on which character is to be expanded. The filename metacharacters are: *: Used to match any number of any characters
?: Used to match exactly one of any character
~: Your home directory
~name: Home directory of the user "name"
[abc]: Used to match any one of the characters in the square brackets (in this case, either an 'a', a 'b', or a 'c'). A dash (-) can be used to denote a range, like [A-M].
{abc,def,ghi}: Expand each comma-seperated string inside the braces.
Let's use ls to show how this works. Because '*' can denote any number of any characters, the command ls * is the same as ls if there are no directories to be listed.
[localhost:~] dr_unix% ls
Adam.txt Documents Movies Pictures Sites temp.html who_list
Desktop Library Music Public personal test_1.txt
[localhost:~] dr_unix% ls *
Adam.txt temp.html test_1.txt who_list
Desktop:
Documents:
6197.txt Movie_1
Acrobat User Data fw9.pdf
AppleWorks User Data iTunes
Library:
Addresses FontCollections Preferences
Application Support Fonts Printers
Assistants Internet Plug-Ins Screen Savers
Audio Internet Search Sites Sounds
Caches Keyboards Speech
ColorPickers Keychains Voices
Documentation Logs iTunes
Favorites Mail
Movies:
Music:
Pictures:
iPhoto Library
Public:
Drop Box
Sites:
images index.html
personal:
[localhost:~] dr_unix%
If you want to suppress the directory expansion with ls so that they are in fact the same, there is the '-d' flag:
[localhost:~] dr_unix% ls -d *
Adam.txt Documents Movies Pictures Sites temp.html who_list
Desktop Library Music Public personal test_1.txt
[localhost:~] dr_unix% ls -d
Adam.txt Documents Movies Pictures Sites temp.html who_list
Desktop Library Music Public personal test_1.txt
[localhost:~] dr_unix%
If you want a list of all the files starting with 'D', or ending with '.txt', or containing 'st' anywhere, just type:
[localhost:~] dr_unix% ls -d D*
Desktop Documents
[localhost:~] dr_unix% ls *.txt
Adam.txt test_1.txt
[localhost:~] dr_unix% ls *st*
test_1.txt who_list
[localhost:~] dr_unix% ls -d d* *.txt *st*
Adam.txt Desktop Documents test_1.txt who_list
[localhost:~] dr_unix%
Note that metacharacters are expanded into a list and then shoved into the command. Notice that, in the example provided here, there are two directories that start with 'D'. If you pass the argument 'D*' to cd,
[localhost:~] dr_unix% cd D*
D*: Ambiguous.
[localhost:~] dr_unix% ls -d D*
Desktop Documents
[localhost:~] dr_unix%
you get an error message (D*: Ambiguous.). What happens is that, behind the scenes, the shell looks for all files that can be described with 'D*', expands that to 'Desktop Documents', and this is passed to the cd command, which becomes cd Desktop Documents. Since cd takes (at most) one argument, the cd command burps. Neat, huh?
'*' is, by far, the most commonly used filename metacharacter, but the others can be quite handy, when needed. (After all, that's why they exist; they are more common in shell scripts, but can be useful on the command line as well.) The '?' metacharacter is used less often, but when it is needed, it's indispensable. It will substitute for any one character, and '?'s can be strung in series to emulate 'any character, a specific number of times':
[localhost:~] dr_unix% ls t*
temp.html test_1.txt
[localhost:~] dr_unix% ls te??.*
temp.html
[localhost:~] dr_unix%
The '[]' metacharacters are mostly used in shell scripting, and rarely then, but again, they're available in Unix for a reason. The shell will match any character that is between the brackets.
[localhost:~] dr_unix% ls
Adam.txt Documents Movies Pictures Sites temp.html who_list
Desktop Library Music Public personal test_1.txt
[localhost:~] dr_unix% ls te*
temp.html test_1.txt
[localhost:~] dr_unix% ls te[mno]*
temp.html
[localhost:~] dr_unix%
If you want to look for a range of characters, you can use the '-' character:
[localhost:~] dr_unix% ls *.txt
Adam.txt test_1.txt
[localhost:~] dr_unix% ls [a-z]*.txt
test_1.txt
[localhost:~] dr_unix%
(Remember, Unix is case-sensitive, so the 'A' character is not the same as the 'a' character.)
In ten years of Unix, I have used the '{}' metacharacters maybe twice, but again, when I needed them, they saved me a lot of work. The shell takes each comma-seperated string in the '{}', expands them into a list, then does whatever else is required.
[localhost:~] dr_unix% ls
Adam.txt Documents Movies Pictures Sites temp.html who_list
Desktop Library Music Public personal test_1.txt
[localhost:~] dr_unix% ls {te}*
temp.html test_1.txt
[localhost:~] dr_unix% ls -d {D,te}*
Desktop Documents temp.html test_1.txt
[localhost:~] dr_unix%
The '{}' is rarely used; in fact, I'd forgotten about it until researching this column. But again, when it is needed, it will save you a lot of work.
Two other metacharacters (which aren't strictly filename metacharacters, but are close enough for government work) are '. and '..'. (I know that I've mentioned them before, but they are worth repeating.) These are present in every directory.
[localhost:~] dr_unix% ls -ad .*
. .DS_Store .Trash .cshrc
.. .FBCIndex .addressbook .ssh
.CFUserTextEncoding .FBCLockFolder .addressbook.lu .tcsh_history
[localhost:~] dr_unix%
'.' is a shorthand for many things. In the context of directories, '.' is a shorthand for 'this directory'.
[localhost:~] dr_unix% ls
Adam.txt Library Pictures personal test_1.txt
Desktop Movies Public sigquotes what_list
Documents Music Sites temp.html who_list
[localhost:~] dr_unix% ls .
Adam.txt Library Pictures personal test_1.txt
Desktop Movies Public sigquotes what_list
Documents Music Sites temp.html who_list
[localhost:~] dr_unix%
Every directory has a '.' directory referring to itself. This may not seem too useful now, but it will be quite handy later on. Using '..', on the other hand, is so common that you will wonder how you ever got on without it. It means 'my parent directory'.
[localhost:~] dr_unix% pwd
/Users/dr_unix
[localhost:~] dr_unix% cd ..
[localhost:/Users] dr_unix% pwd
/Users
[localhost:/Users] dr_unix%
Every directory has a '..' referring to its parent directory. (The one exception is the root directory, '/', in which case it refers to itself.)
Now that we have looked at the filename metacharacters, options, and arguments, and have seen how a couple of the basic commands are used in action, we are ready for some meatier topics. We'll start with manipulating files and directories in the next column.
You are encouraged to send Richard your comments, or to post them below.
Most Recent Mac OS X Command Line 101 Columns
Command Line History & Editing Your Commands
November 22nd
Pico: An Easy To Use Command Line Editor
November 1st
Understanding The "grep" Command In Mac OS X
October 4th
Command Line History & Editing Your Commands
September 6th
Mac OS X Command Line 101 Archives
Back to The Mac Observer For More Mac News!
Richard Burton is a longtime Unix programmer and a handsome brute. He spends his spare time yelling at the television during Colts and Pacers games, writing politically incorrect short stories, and trying to shoot the neighbor's cat (not really) nesting in his garage. He can be seen running roughshod over the TMO forums under the alias tbone1.
|