OS X Terminal
Some time between 2003 and 2008 I wrote this. It's a through discussion of the Terminal and UNIX commands. It was targeted at Mac OS X 10.4. Most of it is still applicable. I am trying to reorganize it and update it.
Before the GUI, there was the terminal
This page assumes you don't have much knowledge of the Terminal but it jumps right in with in-depth information, like why you might want to use sudo rm -- -r /
instead of just sudo rm -r /
, or what happens when you create a file in the Finder with /
in the name, what {,}
does in the shell, the difference between ditto
and cp -R
, why vsdbutil -d
is evil, etc. So I hope it offers something to the newbie and an experienced user.
What and why
"Command line", "command line interface", "terminal", and "shell" are words that describe a text user interface. You interface with the computer by typing text messages on a keyboard. The computer displays text messages back at you.
Why would you want to learn how to use the terminal?
- It was written by programmers for programmers, giving them the ability to do very powerful things.
- I've heard with each OS X update people moaning about getting a new Finder because the current one sucks so bad. Well, the Terminal can do everything Finder can, and faster too!
- If you want to remotely control a computer, ssh access is a very low bandwidth method, and it allows multiple permission levels (unlike VNC) so many users can all remotely access a computer.
- Debugging a computer is sometimes easier with 2 computers, one ssh'ed into the other.
- Shell scripting is very powerful and uses the same commands that the Terminal uses, so you don't need to learn a new way to talk about things (well, once you learn the terminal way to talk about things).
- If your computer wont boot, often it will boot to single user mode, allowing you to look at logs and also allowing you to try to fix it.
For all of these reasons, I'm going to discuss Terminal from the standpoint that we are going to replace the Finder. It can be used as a references, but each section builds on what comes before. While most of this applies to many Unix systems this page is Mac OS X centric. Some commands are only available on Mac OS X.
Where is Terminal?
You can get a Terminal many ways. Probably the most obvious is to open /Applications/Utilities/Terminal.app. If you have X11 installed, open the X11 app and it will open an xterm, which behaves a bit differently than Terminal.app. You can also download several 3rd party terminal applications like iTerm.
Or you can go hardcore and type ">console" at the login prompt instead of your normal username and password (you might have to click the "Other" button if you are using a list of users at loginwindow). You wont be able to launch GUI applications.
Although you probably rarely want to do this (unless you are a system administrator), you can boot to single user mode by holding command-s right after the startup chime. Once the pinwheel appears, it is too late and it has gone to multi user. You will need to restart and try again. If it keeps not working, try holding down option at startup. Does it ask for a password? If it does, you will need to turn Open Firmware password off (Google is your friend).
I'm going to assume you are using Terminal.app.
New window
Finder can have many windows open at once, Terminal can too. Open a new Terminal shell with command-n. This is equivelent to the new Finder window command (and is the same keyboard short cut even).
Find out where you are
Just like a Finder window always is located in some folder, the Terminal is always at some folder as well. When opening a new Terminal window, it will most likely be located in your home directory (aka $HOME
, or ~/
).
If you are unsure where you are, you can type pwd
. This is equivalent to command clicking a Finder window titlebar, only the pwd version can be copied.
Example:
[Computer:/Library] james% pwd
/Library
Notice that my prompt actually tells me where I am.
[Computer:*/Library*]
It will not always tell you the full path though, so pwd is still needed.
Look at a file
To print out an entire file:
cat <filename>
To view a file page by page:
less <filename>
or
more <filename>
("less is more")
Create an empty file
To create an empty file:
touch <newfilename>
Finder can't create files.
The file system keeps track of when files were last changed. If you use touch on a file that already exists, the file contents will not be changed, but the modification date will change the current time (thus, it was "touched" but not changed).
Erase the contents of a file (piping)
To erase (or create a new file).
echo -n > <filename>
To erase a file and put some text in it.
echo "Your text here" > <filename>
To append a line to the end of a file:
echo "Your text here" >> <filename>
Notice the difference is two >>
. Be careful with this because the last thing you want to do is accidentally erase a file by only putting one >
(I've done it).
Arguments/parameters
Commands take options and other arguments and parameters. For example, touch takes the name of the file to create. The name of the file is an argument or parameter.
Unix commands can be given options telling it to do something different. Those are also arguments and parameters. For example, touch -c <filename>
will do something different than the default behavior. When a parameter is an option, like -c
, it is also called a flag or a switch.
Sometimes multiple flags can be combined (in any order usually), like this:
pwd -PL
Or they can be specified individually:
pwd -P -L
Some options use two dashes --option-name
. Two dashes alone --
(no letters after it) indicates there are no more flags. This is so that you can to do something to a file that begins with -
. For example:
[Computer:~/] james% touch -c
usage: touch [-acfm] [-r file] [-t [[CC]YY]MMDDhhmm[.SS]] file ...
Oops, it didn't work but instead told me how I'm suppose to use the command. However, this works:
touch -- -c
This creates a file named -c
.
Looking at the contents of a folder
Naturally the Finder always shows files and folder and gives you information about them and even allows you to "Get Info" so you can see more details and make some changes. You can get the same lists and, in fact, more information than the Finder shows. Use ls
(list) for the basic list. Here are some of the different options:
Shows a quick directory list:
ls
Show a quick list, only one item per line:
ls -1
Show detailed list:
ls -l
Show all files including hidden ones:
ls -Al
Sort the listing by size (largest first):
ls -S
Sort by time, reverse order (newest last):
ls -tr
Look at the contents all of the sub-directories (recursive):
ls -R
Show the locked state of a file (an extra column is shown):
ls -ol
Show the contents of :
ls -l <dirname>
Show but not the contents:
ls -dl <dirname>
How do you read the output of ls -l
?
drwx------ 37 james james 1258 Oct 7 23:01 Desktop
-rw-r--r-- 1 root james 17920 Oct 1 09:55 Desktop DB
-rw-r--r-- 1 root james 113090 Oct 1 21:28 Desktop DF
drwx------ 9 james james 306 Jul 15 22:05 Documents
drwx------ 53 james james 1802 Jun 21 17:38 Library
drwx------ 50 james james 1700 Sep 30 12:44 Movies
drwx------ 20 james james 680 Jul 9 20:22 Music
drwx------ 25 james james 850 Sep 10 22:52 Pictures
drwxr-xr-x 6 james james 204 Oct 8 15:49 Sites
The first character is the type of file/folder. - d Directory. - l Symbolic link. - - Regular file.
The next nine characters rwx------
are the permissions.
The first 3 characters are the "owner" or "user" permissions, the next 3 are the group permissions, the last 3 are permissions for anyone who has access to the computer if it has multiple accounts ("other" or "world").
- r means read access
- w means write access
- x means execute if file, search if folder
See chmod
below for more info on permissions.
The next number tells you how many files are in a folder (including . and .. or any other hidden files) or the number of hard links a file has (don't worry about what that is, by default it will almost always be one).
Next is the user that owns the file. Then you get the group of the file. Then the filesize in bytes. Then you get the last modification date and time. Then you finally get the filename. If the file is a symbolic link (similar to a Finder alias), there will be an arrow showing what file the link points to (try running ls -l /
to see some links).
More options available
To find out what a flag does, or to find out what other flags there are, use man <commandname>
. For example:
man ls
For more information on man, see the next tutorial on finding out everything about commands.
Folder separator character
The forward slash "/" is the folder separator character. No file or folder name can have this character in it. If you create a filename with this character in the Finder, it will let you. But if you look at it from the command line the "/" will be converted to ":".
Example:
drwxr-xr-x 2 james james 68 Oct 7 00:02 adsf:adsf
(In the Finder it appears as "asdf/asdf")
Note, in the Finder, ":" is the folder separation character. You can't create a file with that character in the Finder. But you can in Terminal. If you do, the Finder will display the ":" as a "/". Ok.
/ = root of boot disk
So, look at the root of the hard disk:
[Computer:~] james% ls /
Applications
Desktop DB
Desktop DF
Developer
Icon?
Library
Network
System
TheVolumeSettingsFolder
Users
Volumes
automount
bin
cores
dev
etc
mach
mach.sym
mach_kernel
private
sbin
tmp
usr
var
Surprised? Where did all those things come from? This is what is at the root of your hard disk! The Finder only shows these though:
Applications, Developer, Library, System, Users
That is because it is protecting you from all of that Unix stuff and ls
doesn't.
Hidden files
If a file begins with a period "." (like ".DS_Store") it is invisible in the Finder and with ls
. ls -A
(or ls -a
) is how you view all of the invisible stuff. The Finder will never show you invisible items. Also, the root directory, "/", contains hidden files that are not visible by the Finder but don't begin with ".". The Finder looks at the file "/.hidden" (if it exists) and hides everything listed in the file. Finder also has meta file information that can hide a file that doesn't begin with a dot. You can view this meta information with something like GetFileInfo.
[Computer:/Library] james% /Developer/Tools/GetFileInfo /private
directory: "/private"
attributes: aVbstclinmedz
created: 04/17/2006 23:27:37
modified: 10/02/2006 20:59:54
Notice the V in the attributes line. Capital means it is invisible. (Type "man GetFileInfo" for more information-you must have the developer tools installed.)
To make a file invisible the Unix way just use a period as the first character in the name. Note, the Finder will not let you do this.
To make a file or folder invisible to the Finder, use SetFile.
[Computer:~] james% /Developer/Tools/GetFileInfo /Users/james/Desktop
directory: "/Users/james/Desktop"
attributes: avbstclinmedz
created: 09/13/2006 09:59:23
modified: 10/07/2006 14:57:12
[Computer:~] james% /Developer/Tools/SetFile -a V /Users/james/Desktop
[Computer:~] james% /Developer/Tools/GetFileInfo /Users/james/Desktop
directory: "/Users/james/Desktop"
attributes: aVbstclinmedz
created: 09/13/2006 09:59:23
modified: 10/07/2006 14:57:12
To make it visible, use a lowercase "v".
[Computer:~] james% /Developer/Tools/SetFile -a v /Users/james/Desktop
Absolute paths
An absolute path BEGINS with "/". It specifies the location of a file or folder starting with the root of the hard disk and descending folders. So /Users/mac starts at the root of the hard disk and descends into the "Users" folder and then the "mac" folder.
You don't need to be IN a folder to look at it or do anything in it. This makes Terminal more powerful than Finder, because in the Finder you always have to be in a folder to do anything in it.
For example, my prompt shows I'm in the /Library folder, and I can view other folders without moving to them:
[Computer:/Library] james% ls /Users
Shared james matt
[Computer:/Library] james% ls -1 /Applications
Address Book.app
AppleScript
Automator.app
...
iPhoto.app
iSync.app
iTunes.app
iWeb.app
iWork '06
/Volumes vs /
Why are servers and extra hard disks and media located in /Volumes but the root of the hard disk is at /? Does this mean they are copied to the boot hard disk? Not at all. A Unix file system is actually not an exact representation of the boot hard disk, like you would think. Rather, it is a "file system", meaning all files (and some things that AREN'T files) are accessible from the file system.
To do that, the OS has to "put" everything somewhere. Long ago it was decided that the boot hard disk was the root of the file system, or "/". All other hard disks have to be "mounted" somewhere in that file system (see below for instructions how to do that). Apple decided to mount them in /Volumes. Other Unixes put them in different places and is configurable.
This isn't the only goofy Unixy thing you will encounter either. The contents of the /dev directory are not files or folders either, but I'll just say they are "special" things that need to be accessible in the "file system". You don't want to try to edit them with a text editor.
Moving around
Just like in the Finder where you can move around the folder hierarchy, you can do the same in Terminal using the cd (change directory) command. Note, in Finder you have folders. In Unix you have directories. They are the same thing. However, you earn geek points by using the word directory (it has more syllables).
Go to (valid paths will be discussed below):
cd <path>
Go to your home folder:
cd
Go to the parent directory (in Finder do this by pressing command-up arrow):
cd ..
Toggle to the last location (in Finder click the back and forward button at the top of the window):
cd -
You can also use pushd
and popd
if you plan on toggling around a lot. It was fun when I first used it, but then I realized trying to figure out where I would go the next time I typed popd took longer than just typing cd <path>
.
[Computer:~] james% pushd /
/ ~
[Computer:/] james% pushd Library/
/Library / ~
[Computer:/Library] james% pushd /Applications/
/Applications /Library / ~
[Computer:/Applications] james% popd
/Library / ~
[Computer:/Library] james% popd
/ ~
[Computer:/] james% popd
~
[Computer:~] james%
You don't have to cd
to a folder every time you want to look at it. When I watch new people, they cd
to a folder then immediately ls
, then cd
to another folder inside it, then ls
again, the cd
again, etc. If you know the name of the path, just type the full path (or use tab completion-see below). If you don't know exact paths, and if the folders aren't full of tons of files, you can ls -R
to see everything inside of where you are going. Then you can write one cd
.
Another little Mac OS X trick that I use often is to type open .
(see below for more info). This will open the current directory in the Finder. Then I switch to the Finder column view navigation (command-3 to get that view). Then I use the arrow keys to find what I want. I grab the mouse and drag the location of that window back into the terminal. Click in the Terminal to bring it forwards. Then I press ctrl-a
(see below again) to go to the beginning of the line, then I type cd
. Kinda tricky, but with practice, it is very quick (much quicker than cd ... ; ls ; cd ... ; ls ; cd ...
).
Multiple arguments
Some commands, like cd
, only takes one argument. However, others, like ls
, can take as many as you want. For example:
[Computer:/Library] james% ls -1 /Users/ /Applications/
/Applications/:
Address Book.app
AppleScript
Automator.app
...
iPhoto.app
iSync.app
iTunes.app
iWeb.app
iWork '06
/Users/:
Shared
james
matt
Most commands will take many arguments and do the action on all of them.
Relative paths
A relative path can begin with either a name of a file or folder like "Library", "./", "../", or "~/".
Examples:
The folder named "Library" in the current working directory:
Library
The current directory:
.
or
./
Parent directory:
..
or
../
Your home folder:
~/
More examples of valid (but maybe a bit odd) relative paths (the first cd .
goes to the current directory, basically it doesn't move):
[Computer:~] james% cd .
[Computer:~] james% cd ..
[Computer:/Users] james% cd ../Library/
[Computer:/Library] james% cd ../
[Computer:/] james% cd Library/
[Computer:/Library] james% cd ../Library/
[Computer:/Library] james% cd ../Library/./.././Library/
[Computer:/Library] james% cd ~
[Computer:~] james% pwd
/Users/james
Kinda odd that I'm going in and out of the Library folder, but it is all ok and works.
Tab completion
This needs to be set up
That is a cool shell feature. The way it works is that you type part of a path and then you type the TAB key and the shell tries to figure out what file or folder you want and it fills it in if it can figure it out. For example, if you type "~/M" and press TAB, you have two options "~/Movies" or "~/Music". Because there are 2 options, the shell doesn't know what you want, and it wont complete it but will instead beep at you. Some shells will actually print out the options:
[Computer:~] mac% cd ~/M
Movies/ Music/
[Computer:~] mac% cd ~/M
To give the shell a better chance of figuring out what I really want, I type one more character, the "o". Then I hit TAB and the shell automatically fills in the rest:
[Computer:~] mac% cd ~/Movies/
Sometimes, if tab completion doesn't work, it means you have a misspelling in your path.
Tab completion works with commands too:
system_<tab>
becomes
system_profiler
Spaces in paths (kinda like "Pigs in Space", ok, maybe not)
Old Unix didn't use spaces in paths because spaces means "something new" on the command line. So "/Library/Application Support" is 2 things in Unix: "/Library/Application" and "Support".
Mac OS 9 and below used spaces as if they were saying to all the Unix and DOS people: "Hahaha! We got em and you don't!". But now we have OS X, and now we are cursed with all those old legacy spaces.
Sp to use spaces on the command line, you have two options. You either put quotes around the path or you "escape" the spaces by placing a backslash in front of it, like this: " ". Ok, this really shows that Unix did allow spaces, it just wasn't the norm. These options are the same:
cd "/Library/Application Support"
cd /Library/Application\ Support
Tab completion will really help out here. It will automatically escape your spaces. And if it doesn't tab complete, there is a good chance you typed in the path wrong anyway.
Case insensitive but case preserving
This is a attribute of the HFS+ file system, which is like rude jelly.
Technically, in HFS+, /etc is the same as /ETC. So both of these will work:
ls /etc/
ls /ETC/
However, tab competition is case sensitive, so if get the case wrong, it wont complete for you.
Does nothing (but beep):
ls /E<tab>
Works:
ls /e<tab>
{,} Wildcard
Wildcards are like jokers, they represent things that they aren't. The {,} wildcard allows you to select multiple options, each separated by a comma. In this example, the ls
command lists both Movies and Music:
[Computer:~] james% ls -dl ~/M{ovies,usic}
drwx------ 50 james james 1700 Sep 30 12:44 /Users/james/Movies
drwx------ 20 james james 680 Jul 9 20:22 /Users/james/Music
In this example, the ls
command lists /mach, /mach.sym, and /machkernel. Each is separated by a command, first "" (blank), then ".sym", then "kernel":
[Computer:~] james% ls -l /mach{,.sym,_kernel}
lrwxr-xr-x 1 root admin 9 Oct 2 20:59 /mach -> /mach.sym
-r--r--r-- 1 root admin 615480 Oct 2 20:59 /mach.sym
-rw-r--r-- 1 root wheel 8545336 Sep 27 02:13 /mach_kernel
See below for more examples.
* Wildcard
The wildcard I use most is *
.
Everything:
*
Everything in /
:
/*
Everything in /
that begins with "a" (including "a"):
/a*
Everything in /
that ends with "a" (including "a"):
/*a
Everything in /
that begins and ends with "a" (including "aa"):
/a*a
Everything in /
that has an "a" in it (including "a"):
/*a*
The only exception to "everything" is dot files. To select files that begin with ".", you have to specify the dot:
Everything hidden in /
:
/.*
Everything hidden in /
that begins with "a" (including "a"):
/.a*
Everything hidden in /
that ends with "a" (including "a"):
/.*a
Everything hidden in /
that begins and ends with "a" (including "aa"):
/.a*a
Everything hidden in /
that has an "a" in it (including "a"):
/.*a*
If you want to select both at the same time, use {,} with *:
ls -l {,.}*
A more realistic example:
ls thumb*.jpg
You can also use it in paths. For example:
[Computer:~/] james% ls -l /Library/*/Apple
total 0
drwxrwxr-x 3 root admin 102 Jan 13 2006 Automator
drwxrwxr-x 7 root admin 238 Jan 14 2006 Chinese Input Method Plugin Samples
drwxrwxr-x 13 root admin 442 Aug 1 11:58 Developer Tools
drwxrwxr-x 3 root admin 102 Jan 14 2006 Grapher
drwxrwxr-x 5 root admin 170 Oct 4 16:55 Remote Desktop
drwxrwxr-x 4 root admin 136 Aug 1 18:02 System Image Utility
drwxrwxr-x 11 root admin 374 Aug 17 21:08 iChat Icons
What folder am I looking at though? I don't know. Here is how I find out:
[Computer:~/] james% ls -ld /Library/*/Apple
drwxrwxr-x 9 root admin 306 Oct 4 16:55 /Library/Application Support/Apple
What if there were multiple folders found.
[Computer:~/] james% mkdir /Library/Preferences/Apple
[Computer:~/] james% touch /Library/Preferences/Apple/hahaha
[Computer:~/] james% ls -l /Library/*/Apple
/Library/Application Support/Apple:
total 0
drwxrwxr-x 3 root admin 102 Jan 13 2006 Automator
drwxrwxr-x 7 root admin 238 Jan 14 2006 Chinese Input Method Plugin Samples
drwxrwxr-x 13 root admin 442 Aug 1 11:58 Developer Tools
drwxrwxr-x 3 root admin 102 Jan 14 2006 Grapher
drwxrwxr-x 5 root admin 170 Oct 4 16:55 Remote Desktop
drwxrwxr-x 4 root admin 136 Aug 1 18:02 System Image Utility
drwxrwxr-x 11 root admin 374 Aug 17 21:08 iChat Icons
/Library/Preferences/Apple:
total 0
-rw-r--r-- 1 james admin 0 Oct 7 00:36 hahaha
Well, it tells me what the folders are. The above command is the same as just giving ls 2 paths (really, that is exactly what the shell does, it gives the command the 2 paths, the command doesn't ever see the wildcard):
ls "/Library/Application Support/Apple" "/Library/Preferences/Apple"
What if I try to cd
to that?
[Computer:~/] james% cd /Library/*/Apple
tcsh: /Library/*/Apple: Ambiguous.
Oops, it wont let me. This is because cd
only takes on argument.
Tab completion doesn't work with wildcards.
Root
Do something as root (sudo will ask for password)
sudo ...
Become root user
sudo -s
sudo
means super user do. Don't mix this up with su
, which means substitute user.
If you have set a root password (by default Mac OS X does not have one set), then you can also do this:
su root
When you are root, you can freely su
to other user accounts.
To leave root, type exit
.
Moving files/folders
Move a file:
mv <filename> <newlocation>
<newlocation>
must be a folder that exists already, mv will not create folders for you.
Move several files:
mv <filename1> <filename2> <newlocation>
Renaming files/folder
The rename command is exactly the same as the move command. The idea is that you are "moving it from one name to another".
mv <oldfilename> <newfilename>
Or using the {,} wildcard:
mv {<oldfilename>,<newfilename>}
Example:
mv oldname newname
The above command is exactly the same as the following (only less typing, and geekier):
mv {old,new}name
Example renaming:
[Computer:~] james% mkdir oldname
[Computer:~] james% ls -dl *name
drwxr-xr-x 2 james james 68 Oct 10 18:06 oldname
[Computer:~] james% mv oldname newname
[Computer:~] james% ls -ld *name
drwxr-xr-x 2 james james 68 Oct 10 18:06 newname
[Computer:~] james% mv {new,newer}name
[Computer:~] james% ls -ld *name
drwxr-xr-x 2 james james 68 Oct 10 18:06 newername
You can rename and move at the same time:
[Computer:~] james% touch blah
[Computer:~] james% mv blah newername/bla
[Computer:~] james% ls -l *name
-rw-r--r-- 1 james james 0 Oct 10 18:06 bla
Making directories
Create a new directory:
mkdir <dirname>
Create a bunch of new directories inside of each other
mkdir -p <dirname/dirname/dirname>
Create a bunch of new directories
mkdir -p <dirname1> <dirname2> <dirname3>
Deleting
WARNING, THESE CAN NOT BE UNDONE (unlike move to Trash)!
Delete a file:
rm <filename>
Delete a directory (if empty):
rmdir <dirname>
Delete a directory (doesn't matter if it is empty or not-DANGEROUS, BE CAREFUL!!!!!!!!!!!!!):
rm -r <dirname>
Delete a bunch of files:
rm <file1> <file2> <file2> ...
Erase your home folder (not wise):
rm -r ~/
Erase your boot disk (I can admit to doing this once on a test box on purpose just to see what would happen, it was fun!):
sudo rm -r /
Secure delete:
srm <file>
Delete a file named "-r":
rm -- -r
How to cause rm -r
to fail:
[Computer:~/asdf] james% touch -- -r
[Computer:~/asdf] james% rm -r *
usage: rm [-f | -i] [-dPRrvW] file ...
unlink file
[Computer:~/asdf] james% ls -l
-rw-r--r-- 1 james james 0 Oct 10 22:40 -r
Oops, that can cause a lot of havoc to scripts. How to safely delete files:
[Computer:~/balladsf] james% rm -r -- *
I suppose I should update all of my scripts that only use rm -r <path>
.
Open stuff
Open a file:
open <filename>
Open a file with TextEdit:
open -e <filename>
Open a file with default text editor (determined by LaunchServices-the "Open With" setting in Get Info):
open -t <filename>
Open a file with a particular application:
open -a <path to app> <filename>
Open a directory (in Finder):
open <directory>
Launch an application:
/path/to/application.app/Contents/MacOS/appname
Example
/Applications/Safari.app/Contents/MacOS/Safari
If you run an app using the above technique, it is no different than running any other command, such as rm
. The difference is that rm
runs and quits very quickly (well, sudo rm -r /
will probably take awhile). If you want to launch the app and keep using the terminal, then just "detach" it by putting a space and ampersand at the end, like this:
/Applications/Safari.app/Contents/MacOS/Safari &
Any app can print to the terminal, and that is exactly what command line apps do. GUI apps can do that too, but most do not. So if you use the ampersand, and text suddenly appears in your terminal, it could be from the command you detached. The text does nothing, so you can ignore it if you want (and if you can-you may need to clean up your display).
Copy
Copy a file
cp filename new_location/
Duplicate a file/directory:
ditto <copy contents of dir> <to dir>
cp -R <copy dir> <to dir>
ditto
and cp
behave differently if the destination folder exists! ditto
is a Mac OS X utility.
Create a duplicate of the Desktop folder and name the new folder Desktop2 (Desktop2 does not exist):
ditto ~/Desktop ~/Desktop2
Same as the ditto
command except a different name (Desktop3 does not exist)
cp -R ~/Desktop ~/Desktop3
Desktop2 exists, copy the contents of Movies into Desktop2:
ditto ~/Movies ~/Desktop2
Desktop3 exists, make a new folder named Movies in Desktop3:
cp -R ~/Movies ~/Desktop3
Notice how cp
and ditto
behave very different if the destination folder exists! cp
will create a new folder in the destination. ditto
will copy the contents of the source folder to the destination folder! Very different.
File owner or group
Every file and folder is "owned" by a user account. Use chown
and chgrp
to change who owns what. You can do this in the Finder with the "Get Info" dialog.
Change the owner:
sudo chown <username> <path>
Change the owner of everything in a folder:
sudo chown -R <username> <path>
Multiple owners can modify a file if they are in the same group as the file. That is what group is used for.
Change the group:
sudo chgrp <groupname> <path>
Change the group of everything in a folder:
sudo chgrp -R <groupname> <path>
Change permissions
Each file has a set of permissions associated with it. The permissions is called the "mode". This was talked about already in the ls
section. However, there is more to know!
You do some of this in Finder in the "Get Info" dialog. The part you can't do in the Finder is change the x setting. Changing the x setting can bust stuff if you don't know what you are doing.
Change the mode:
chmod <mode> <path>
Change the mode of everything in a folder:
chmod -R <mode> <path>
Modes can be specified two ways: what you want done, or a number that represents all of the permissions.
The "what you want done" method is easy. You specify the "user" (aka owner), the group, or "other" (aka world) and then the operation (- or +) and the permission you want changed (r, w, or x). So if I wanted to give other write permission to /etc/crontab (which is a very bad idea), I use this command:
sudo chmod o+w /etc/crontab
If I wanted to remove world write permissions for every user to every file (another bad idea), I use the command:
sudo chmod ugo-w /
A number permission is fairly easy to read and you only use a few combinations anyway.
r means read access (value of 4)
w means write access (value of 2)
x means execute if file, search if folder (value of 1)
Add up the values to get a number (octal) representation of the permissions:
rwx = 7
rw- = 6
r-x = 5
r-- = 4
-wx = 3
-w- = 2
--x = 1
--- = 0
You will usually only use 7, 6, 5, and 4.
Then because there are 3 categories of users, there are 3 of these numbers in a row:
rwxrwxrwx = 777
rwxr-xr-x = 755
rw-r--r-- = 644
Folders and executable binaries or scripts should be set to this permission:
775 (rwxrwxr-x)
or
755 (rwxr-xr-x)
It is common for files (that aren't scripts or executables) to be set to this permission:
664 (rw-rw-r--)
or
644 (rw-r--r--)
Usually 7 and 5 go together (rwx and r-x) and 6 and 4 go together (rw- and r-). The only times I've seen 766, 744, 655, or other combinations like that is when someone didn't know what they were doing (733 on a folder is actually a drop box, so old modes aren't always wrong, just rare).
There is also more mode information like SUID bit, sticky bit, etc.,. Just ignore them because you shouldn't mess with them if you don't already know what they are. That extra mode information is at the beginning of the number, making it a 4 digit number. Usually that number is 0 (meaning no extra info). So you might see 0755 and 0644 for example.
If you see 0777 (rwxrwxrwx) that is a good sign somebody didn't know what they are doing. It means that anyone who has an account on your computer can make changes to that file or folder. In most cases, this doesn't matter because Mac OS X is sold to consumers who only give accounts to their family. However, in a multiuser environment like a school lab or a server, 0777 is not a good idea. If you look at /private/tmp, you will see this permission: drwxrwxrwt (1777). Notice the "t"? This is a safe way of doing 777. Yes you can chmod +t <file>
.
File locking
In the Finder, you can select "Get Info" on any file or folder and there is a checkbox to "Lock" it. This makes it so you can't delete or change the file. You can do this in the Terminal too.
Lock a file/folder:
chflags uchg <path>
Lock a directory and everything in it:
chflags -R uchg <path>
Unlock a file:
chflags nouchg <path>
Unlock a directory and everything in it:
chflags -R nouchg <path>
Recursive
Command line tools do things to files and directories. Several of them will do things to everything in a directory (recursion). Getting a command to behave recursively depends on the command.
Some tools use -r, some -R. There is kinda a pattern. Most tools use lower case ("-r"). The tools (that I know of) that use upper case are ls
, cp
, and the ch*
commands (chmod
, chown
, chgrp
, and chflags
). ls -r
just reverses the sort order, so if you use it, no harm will be done (you just don't get what you wanted). chmod -r
will remove read permissions (oops). The other ch* commands don't respond to -r. Again, the other tools use lower case ("-r").
If in doubt, try man <toolname>
and look at the available options.
When using recursion with the * wildcard, there is a slight difference.
chmod -R someuser ~/
The above is different from:
chmod -R someuser ~/*
The first specifies the ~/ folder and all of its contents. The second specifies all of the contents of ~/, but not the folder ~/.
Make symbolic link
This is similar to a Finder alias, but they are NOT the same.
ln -s <realfile> <linkfile>
When you ls a symbolic link, it looks like this:
lrwxr-xr-x 1 root admin 11 Apr 18 07:29 tmp -> private/tmp
Notice the first character is "l". Also notice the arrow pointing right. When creating a symbolic link, just remember that the arrow points the opposite direction: realfile <- linkfile (ls is linkfile -> realfile, see how it is different?)
If you want to create a real Finder alias from the command line, use OSXUtils.
Find a file
find <path> <criteria> <commands>
Examples:
[Computer:/etc] james% sudo find /private/etc -name "host*" -print
/private/etc/hostconfig
/private/etc/hosts
/private/etc/hosts.equiv
/private/etc/hosts.lpd
[Computer:~] james% find ~/.Trash -name ".DS_Store" -print -delete
/Users/james/.Trash/.DS_Store
/Users/james/.Trash/build/.DS_Store
/Users/james/.Trash/build/Release/.DS_Store
/Users/james/.Trash/build 23-02-55/Release/.DS_Store
/Users/james/.Trash/untitled folder/.DS_Store
[Computer:~] james% find ~/.Trash -name ".DS_Store" -print -delete
[Computer:~] james%
In the last command there were no files left to delete!
Finding files vs directories and executing a command on the found set:
find /var/radmind/transcript -type d -exec /bin/chmod 770 '{}' ;
find /var/radmind/transcript -type f -exec /bin/chmod 660 '{}' ;
find
can find files using many qualifiers, like permissions, size, path, modification date, older, newer, etc. man find
to see the list.
You can also use Spotlight from the command line!
mdfind <text to find>
Example:
[Computer:~] james% mdfind modo
/Library/Application Support/Luxology/Documentation/help/pages/Stretch.html
/Library/Application Support/Luxology/Documentation/help/pages/Subdivide.html
/Library/Application Support/Luxology/Documentation/help/pages/Subdivision_Level.html
...
/Users/james/Library/Mail/IMAP-james@-----.com/mail/sent-mail.imapmbox/Messages/347181.emlx
/Users/james/Library/Mail/IMAP-james@-----.com/mail/sent-mail.imapmbox/Messages/347819.emlx
/Users/james/Library/Mail/IMAP-james@-----.edu/Sent Messages.imapmbox/Messages/348825.emlx
/Users/james/WherezModo/source/Controller.h
/Users/james/WherezModo/source/Controller.m
/Users/james/Desktop/unix/Tutorial
Here is another interesting example searching for world writable locations (output seriously shortened because it was so long.):
[Computer:~] james% /usr/bin/find / ! -type l -perm -2
/.Trashes
/Applications/Adobe/Adobe Version Cue CS2/config/StartupOptions.xml
/Applications/DivX Converter/DivX Converter.app
/dev/tty
/Library/Application Support/Adobe/Adobe Registration Database
/Library/Audio/Apple Loops Index
/Library/Caches
/Library/Internet Plug-Ins/DRM Plugin.bundle
/Library/Preferences/Adobe Systems
/Library/Printers/EPSON/CIOSupport/Preferences
/Library/Printers/Lexmark/Preferences
/Library/ScriptingAdditions
/Library/ScriptingAdditions/Adobe Unit Types
/private/etc/opt/cisco-vpnclient
/private/tmp
/private/tmp/mysql.sock
/private/var/run/asl_input
/private/var/spool/samba
/private/var/tmp
/private/var/tmp/mds
/Users/Shared
/Users/Shared/GarageBand Demo Songs
/Volumes
And this command turned up some interesting finds (output pruned again):
[Computer:/System/Library] james% find . -type f -perm -1 -print
./Frameworks/ApplicationServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister
./CoreServices/RemoteManagement/AppleVNCServer.bundle/Contents/Support/LockScreen.app/Contents/MacOS/LockScreen
./CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart
./CoreServices/Software Update.app/Contents/Resources/SoftwareUpdateCheck
I tested a few and a few of the commands actually did things:
[Computer:/] james% "/System/Library/CoreServices/Software Update.app/Contents/Resources/SoftwareUpdateCheck"
2006-10-12 23:04:23.754 SoftwareUpdateCheck[11716] Checking for updates
(The software update window appeared and showed my all of my out of date Apple software!)
I cheated, I already knew about this one:
[Computer:] root# /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -help
kickstart -- Quickly uninstall, install, activate, configure, and/or restart
components of Apple Remote Desktop without a reboot.
kickstart -uninstall -files -settings -prefs
-install -package <path>
...
I knew about this one too:
[Computer:/] james% /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister
lsregister: [OPTIONS] [-domain { system | local | user | network }]... [path]...
Search the paths for application bundles and add each found item to the Launch
Services database. For domain specifications, ask CF for the list of application
locations in the given domain(s).
-kill Reset the global Launch Services database before doing anything else
-lint Print information about plist errors while registering bundles
-convert Register apps found in older LS database files
-lazy n Sleep for n seconds before registering apps if the local cache
is aleady populated.
-r Recursively register directory contents, do not recurse into
packages or invisible directories.
-R Recursively register directory contents, including the contents
of packages and invisible directories.
-f force-update registration info even if mod date is unchanged
-v Display progress information.
-dump Display full database contents after registration.
-h Display this help.
Clear the screen
There is the command:
clear
And the keyboard shortcut:
ctrl-l
And in Terminal.app you can use command-K to clear the screen and the "scrollback". This is sometimes helpful if you need to run a command that prints a lot of text, because you can press home key to see the top of the output and page down to read it. This is much easier than trying to scroll up and see where you started the command with a full scrollback. You can set the scrollback length to unlimited in the Terminal prefs if you have really long winded commands.
History
The shell keeps track of what commands you type. This is a feature of the shell, not the application. This will print out a list of all remembered commands:
history
You've also got keyboard shortcuts:
up arrow - history up one word
down arrow - history down one word
When using the up arrow, you can use the ctrl-a
key to jump to the beginning of the line and then esc-f
to go forward each word until you get where you want to change it (I hate watching people hold down left arrow to the start of the line).
And there is history search:
<typeletters> esc-p - history search backwards (does not work on BASH)
<typeletters> esc-n - history search forwards (does not work on BASH)
History search is similar to tab completion, you can start typing a command, but instead of hitting TAB to complete the command, use esc-p
and it will complete it with whatever it finds in the history that matches the first part you've typed already. Keep pressing esc-p
or esc-n
to move up or down through the history.
The history is saved to a file, either ~/.bashhistory or ~/.tcshhistory. This is a VERY GOOD REASON to NEVER TYPE A PASSWORD. If you do, you want to close all your terminal windows and then erase the history then open a new terminal window, then close the old one, then close the new one. Only after doing that complicated routine is the password really gone. Really, just don't type your password in a command.
This is why you need to do all of that to clear the history (and why the history isn't 100% accurate).
When a new terminal window is opened, it reads the history file and then every command you type after that is remembered by that window (but not written to the history file). When you close the window, the remembered history is written to the history file, including the old history it loaded when you opened the window.
If you open 2 Terminal windows at the same time, each will read the history file. If you type "bad things" in window A and close it, it will save "bad things" to the history file. If you then type "good things" in window B, then close it, it will OVERWRITE the history window A just saved with window B's history, thus erasing "bad things".
It is kinda complex. Just don't expect the history to remember every command you type. If you catch the hang of it, you can at least be aware of when you accidentally blow away the history (which I've done in agony). Of course you can avoid doing that by just keeping one Terminal window open, but I can't stand that and typically have a minimum of 3 open on my work computer, and sometimes as many as 10.
Bindkey
Typing in the terminal can be a slow process, especially if your key repeat rate is slow (mine is all the way up-yours should be too). Luckily, there are some short cuts that let you move around quickly.
First of all, go to "Terminal" menu, "Window Settings", "Emulation" pop-up, and check "Option click to position cursor". Now you can option click and the cursor will try to move to that location. Terminal.app does this by using the keyboard arrow keys to move the cursor around (or something). What that means is that if it hits a tab, or some other strange character, the cursor will not actually move to the location you clicked, but it will be off. So you may have to option click a few times to get it to the right spot. It is better than just the arrow keys so be happy.
Moving around:
ctrl-a - move to beginning of line
ctrl-e - move to end of line
esc-b - skip backwards a ward at a time
esc-f - skip forwards a word at a time
Cut and paste:
ctrl-d - deletes the charcter **after** the cursor (opposite of the delete key)
esc-backspace - delete letters before the cursor to the next space (word delete)
esc-d - delete letters after the cursor to the next space (word delete)
ctrl-u - delete whole line
ctrl-k - delete from cursor to end of line)
ctrl-w - delete from cursor to begin of line)
ctrl-y - yank, puts back what ctrl-u/k/w removed (acts like paste)
esc-y - cycle through yank
esc-d
Very important:
ctrl-c - cancel
End of Line:
ctrl-d - when in input mode (haven't mentioned that yet, but `grep a` is an easy way to get there), exit with cntl-d
Change case:
esc-u - make word uppercase
esc-l - make word lowercase
To see all options, type bindkey
if you are using TCSH or bind -p
if you are using BASH.
Open a CD tray
drutil eject
Use scripts that synchronize their times with their IP and send the command via Apple Remote Desktop that open and close the trays of rows of computers in front of large crowds of Apple system admins in order to pretend that you are Steve Hayman.
Mount a disk image file (dmg)
hdiutil mount <file.dmg>
[Computer:~/Desktop] james% hdiutil mount *dmg
Checksumming Single Volume (Apple_HFS : 0)...
.................................................................................
Single Volume (Apple_HFS : 0): verified CRC32 $A1000E0F
verified CRC32 $DAAF9163
/dev/disk2 /Volumes/SomeDMG
Unmounting:
[Computer:~/Desktop] james% hdiutil unmount /Volumes/SomeDMG
"disk2" unmounted successfully.
Ignoring permissions of a mounted volume
Apple allows users to bypass Unix permissions on mounted volumes. To check to see if permissions are ignored on a volume:
vsdbutil -c /Volumes/Diskname
To ignore permissions on the volume:
vsdbutil -d /Volumes/Diskname
To use Unix permissions on a volume:
vsdbutil -a /Volumes/Diskname
For example:
[Computer:/] root# vsdbutil -c /Volumes/Disk
Permissions on '/Volumes/Disk/' are enabled.
Permissions are on.
[Computer:/] root# ls -l /Volumes/Disk
...
-rw-r--r-- 1 james admin 994 Jul 12 13:39 getip.pl
-rwxr-xr-x 1 rootadmin 433544 Jun 26 14:12 hping_fat
drwxrwxr-x 3 unknown unknown 102 May 12 11:45 iMacSMCUpdate.pkg
-rwxr-xr-x 1 unknown unknown 2374 Dec 28 2005 indexLoops
drwxr-xr-x 30 james admin 1020 Sep 5 11:18 modo
drwxrwxrwx 52 unknown unknown 1768 Sep 19 21:53 ruby
drwxr-xr-x 10 unknown unknown 340 Sep 19 21:53 textmate
-rw-r--r-- 1 unknown unknown 983820084 Aug 15 15:47 xcode_2.4_8k1079_6936199.dmg
Notice the unknown user and group? That is because I created those files while permissions were off. I'll now turn off permissions, and see what havoc breaks loose.
[Computer:/] root# vsdbutil -d /Volumes/Disk
[Computer:/] root# vsdbutil -c /Volumes/Disk
Permissions on '/Volumes/Disk/' are disabled.
Permissions are now off. Notice I'm the root user.
[Computer:/] root# ls -l /Volumes/Disk
-rw-r--r-- 1 unknown unknown 994 Jul 12 13:39 getip.pl
-rwxr-xr-x 1 unknown unknown 433544 Jun 26 14:12 hping_fat
drwxrwxr-x 3 unknown unknown 102 May 12 11:45 iMacSMCUpdate.pkg
-rwxr-xr-x 1 unknown unknown 2374 Dec 28 2005 indexLoops
drwxr-xr-x 30 unknown unknown 1020 Sep 5 11:18 modo
drwxrwxrwx 52 unknown unknown 1768 Sep 19 21:53 ruby
drwxr-xr-x 10 unknown unknown 340 Sep 19 21:53 textmate
-rw-r--r-- 1 unknown unknown 983820084 Aug 15 15:47 xcode_2.4_8k1079_6936199.dmg
That's different. Now I'll become the user named "mac" (a local account on my computer) and look at the permissions.
[Computer:/] root# su mac
[Computer:/] mac% ls -l /Volumes/Disk
-rw-r--r-- 1 mac mac 994 Jul 12 13:39 getip.pl
-rwxr-xr-x 1 mac mac 433544 Jun 26 14:12 hping_fat
drwxrwxr-x 3 mac mac 102 May 12 11:45 iMacSMCUpdate.pkg
-rwxr-xr-x 1 mac mac 2374 Dec 28 2005 indexLoops
drwxr-xr-x 30 mac mac 1020 Sep 5 11:18 modo
drwxrwxrwx 52 mac mac 1768 Sep 19 21:53 ruby
drwxr-xr-x 10 mac mac 340 Sep 19 21:53 textmate
-rw-r--r-- 1 mac mac 983820084 Aug 15 15:47 xcode_2.4_8k1079_6936199.dmg
The user named "mac" owns all those files! Now I'll become a different user and see what happens.
[Computer:/Volumes] mac% exit
exit
[Computer:/Volumes] root# su james
[Computer:/Volumes] james% ls -l Radmind Ignores/
-rw-r--r-- 1 james james 994 Jul 12 13:39 getip.pl
-rwxr-xr-x 1 james james 433544 Jun 26 14:12 hping_fat
drwxrwxr-x 3 james james 102 May 12 11:45 iMacSMCUpdate.pkg
-rwxr-xr-x 1 james james 2374 Dec 28 2005 indexLoops
drwxr-xr-x 30 james james 1020 Sep 5 11:18 modo
drwxrwxrwx 52 james james 1768 Sep 19 21:53 ruby
drwxr-xr-x 10 james james 340 Sep 19 21:53 textmate
-rw-r--r-- 1 james james 983820084 Aug 15 15:47 xcode_2.4_8k1079_6936199.dmg
Now the user "james" owns the files!
What does this mean? If you allow other users SSH access to your computer and you think that they can't access mounted volumes, you better make sure by checking that permissions are not ignored. If permissions are ignored on a volume, every user that logs in will be the owner of everything on that volume.
Mount an AFP volume
Mounting a disk is an existential act. First, you must have a plain (but empty) folder. If you want, you can create a new one using mkdir
. For example:
[Computer:/Volumes] james% mkdir "/Volumes/A Very New Disk"
[Computer:/Volumes] james% ls -l
total 8
drwxr-xr-x 2 james admin 68 Oct 7 20:52 A Very New Disk
lrwxr-xr-x 1 root admin1 Sep 27 09:35 Macintosh HD -> /
It's there. But it's empty:
[Computer:/Volumes] james% ls -l "/Volumes/A Very New Disk"
[Computer:/Volumes] james%
Now you can proceed.
Mount a volume (so you don't have to type your password, which keeps the password out of the history file):
mount_afp -i afp://user@server.example.com/Disk_Name "/Volumes/A Very New Disk"
Mount a volume with the password (for a script):
mount_afp afp://user:password@server.example.com/Disk_Name /Volumes/A Very New Disk"
If the disk mounts and the Finder doesn't notice, try this to update the Finder:
disktool -r
To unmount it:
umount /Volumes/A Very New Disk
Very simple (yet very mystical).
Another example mounting the disk in your home directory:
[Computer:~] james% mkdir Radical
[Computer:~] james% mount_afp -i afp://secret@secret.example.com/A Disk Radical
Password:
mount_afp: the mount flags are 0000 the altflags are 0020
The disk name is "A Disk" but the mount point is "Radical". And even more interesting is that "Radical" is located in my home directory! After I did this, Finder hid "Radical" from me and instead put it in my sidebar (how helpful). Terminal did the correct thing and allowed me to cd
into it and do what I wanted. I don't know why Finder would go through the trouble to hide it. After all, it is very unlikely that a user would accidentally mount something in their home folder.
Find disk usage
Terminal can tell you how much space you have left just like the Finder.
[Computer:~] james% df -lh
Filesystem Size Used Avail Capacity Mounted on
/dev/disk0s2 74G 68G 5.8G 92% /
/dev/disk1s2 74G 68G 5.8G 92% /Users/james
I happen to be using encrypted home folders, and wouldn't you know it, /Users/james is a mounted disk! It is kinda odd it is the same size as the hard disk though.
And ironically, no matter how big hard drives get, I always push my usage above 90%.
Display the amount of disk space a folder/file is taking up.
du -hd0 <path>
It counts everything right then and there, so if you run du -hd0 /
, you might want to go find something else to do.
2.3G /System/
Change the number after the d option to show more details. For example 3 shows the sizes of everything 3 levels deep:
[Computer:/Applications] james% du -hd3 /Library/Application Support/Luxology/modo 201/Documentation
8.0K /Library/Application Support/Luxology/modo 201/Documentation/help/common/css
56K /Library/Application Support/Luxology/modo 201/Documentation/help/common/img
4.0K /Library/Application Support/Luxology/modo 201/Documentation/help/common/script
68K /Library/Application Support/Luxology/modo 201/Documentation/help/common
525M /Library/Application Support/Luxology/modo 201/Documentation/help/pages/clips
18M /Library/Application Support/Luxology/modo 201/Documentation/help/pages/imgs
1.6G /Library/Application Support/Luxology/modo 201/Documentation/help/pages/video
2.1G /Library/Application Support/Luxology/modo 201/Documentation/help/pages
2.2G /Library/Application Support/Luxology/modo 201/Documentation/help
2.2G /Library/Application Support/Luxology/modo 201/Documentation
Thus we see that "help/pages/video" is 1.6 GB and "help/pages/clips" is 525 MB, totaling 2.1 GB, the bulk of modo's documentation (each folder contains video files).
Creating an archive
This will create archivename.zip and will include every file you specify:
zip archivename.zip file1 file2 etc
This will create archivename.zip of the contents of "folder":
zip -r archivename.zip folder
Hey folks, you can use tar too:
tar cfvz archivename.tgz file1 file2 etc
tar cfvz archivename.tgz folder
You can double click on these in the Finder to open them (the tgz too). Or you can uncompress them from Terminal too:
unzip archivename.zip
tar xfvz archivename.tgz
A note about tar
. It has many purposes, and creating tgz files isn't the main one, so that is why you have to type so much to get it to do it. Just remember c stands for compress, x for extract, and fvz all kinda make similar sounds (and are all typed with the right hand on a qwerty keyboard). O:)
Restart
sudo reboot
sudo shutdown -r now
You need to be root to restart a computer obviously.
Shutdown
sudo shutdown -h now
Example:
[remote-computer:~] root# shutdown -h now
Shutdown NOW!
shutdown: [pid 12792]
[remote-computer:~] root#
*** FINAL System shutdown message from mac@james-tech-mac-1.scl.utah.edu ***
System going down IMMEDIATELY
System shutdown time has arrived
Stopping Network Information Service
Stopping Apache web server
Stopping network time synchronization
/usr/sbin/apachectl stop: httpd (no pid file) not running
Starting...
Stopped ARD Helper.
Stopped ARD Agent.
Stopped VNC Server.
Done.
Connection to remote-computer.example.com closed by remote host.
Connection to remote-computer.example.com closed.
[Computer:/Volumes] root# ping 12.34.56.78
PING 12.34.56.78 (12.34.56.78): 56 data bytes
^C
--- 12.34.56.78 ping statistics ---
10 packets transmitted, 0 packets received, 100% packet loss
Oops. Now what? Guess I'll have to wait until I get to work on Monday.
Logout
killall loginwindow
Ok, that really isn't the real way to logout. But it IS quick and works.
Although this should work, it doesn't:
osascript -e 'try' -e 'ignoring application responses' -e 'tell application "loginwindow" to «event aevtrlgo»' -e 'end ignoring' -e 'end try'
I'm assuming it doesn't work because it can't wrap its head around the chevron characters.
Determined not to be thwarted, I came up with this awkward solution. First, you have to create the script on your local machine. If you don't mind using Script Editor.app, save the following as logout.scpt:
echo try
ignoring application responses
tell application "loginwindow" to «event aevtrlgo»
end ignoring
end try
Then run this command to get a hexdump of it:
cat logout.scpt | perl -ne 'print unpack "H*", $_'
Mine prints out this:
4661736455415320312e3130312e31300e000000040fffff00010002000301ff
ff00000d000100026c00020000001c0004fffe0d000400035100000000001c00
050006fffd0d00050003500000000300130007fffc00080d000700024f000100
0800120009000a0d00090003490002000c0011fffbfffafff90afffb00182e61
657674726c676f2a2a2a2a00000000000090002a2a2a2a01fffa000002fff900
000d000a00016d000000080009000b0f000b01d8086e756c6c000000000001df
80ff9c000975b30f6c6f67696e77696e646f772e617070db3016488280000000
800000000100000001a001021890045ff8bfffd9d0bfffdbe190046044991e50
d8bfffd9d0bfff6c676e7700001100616c697300000000017a00020001084d61
63204f53205800000000000000000000000000000000000000bf145f5d482b00
00000975b30f6c6f67696e77696e646f772e6170700000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
00000000000009991abf140d330000000000000000ffffffff00000920000000
0000000000000000000000000c436f72655365727669636573001000080000bf
14b3bd0000001100080000bf14619300000001000c000975b300090bf500090b
f3000200344d6163204f5320583a53797374656d3a4c6962726172793a436f72
6553657276696365733a6c6f67696e77696e646f772e617070000e0020000f00
6c006f00670069006e00770069006e0064006f0077002e006100700070000f00
120008004d006100630020004f0053002000580012002b53797374656d2f4c69
62726172792f436f726553657276696365732f6c6f67696e77696e646f772e61
707000001300012f00ffff000002fffc00000200080002fff8fff70afff80008
0b636f6e73726d746502fff700000d0006000352000000000000fff6fff5fff4
0afff600182e61736372657272202a2a2a2a00000000000090002a2a2a2a01ff
f5000002fff4000001fffd000001fffe00000e000200000f1000030003fff300
0c000d01fff3000010000c0001fff20afff200182e616576746f6170706e756c
6c00008000000090002a2a2a2a0e000d000710fff1000efff0ffef000f0010ff
ee0afff100182e616576746f6170706e756c6c00008000000090002a2a2a2a0d
000e00016b00000000001c001102001100020001ffed02ffed000001fff00000
02ffef000010000f000010001000050008000bffecffebffea0affec00182e61
657674726c676f2a2a2a2a00000000000090002a2a2a2a01ffeb000002ffea00
0011ffee001d14001567e013000de11200072a6a0c0002555657000858000300
04680f00617363720001000dfadedead
Copy that. Then on the remote machine, type "pico logout.hex" (see below for more info on pico). Paste. Type ctrl-x
to save the file and exit pico. Then type this:
perl -e 'chomp ( $hex = `cat logout.hex`);' -e 'print pack "H*", $hex' > logout.scpt
Then to logout, type
osascript logout.scpt
This will not ask to logout. However, if an app refuses to quit, logout will be canceled. So if after, say, 30 seconds you haven't logged out, run top, look to see what is still running, and you can kill it or you can actually tell it to quit with this command:
osascript -e 'tell application "Terminal" to quit'
If it doesn't respond to that, perhaps it has a sheet asking for user input. I suppose you could use UI scripting to click "OK" or whatever, but even I have to say that is excessive.
However, what if you aren't sure what is going on? If the screensaver on the remote machine isn't running, you can see what the screen looks like with this command:
screencapture filename.png
Then scp
that file to your machine and voilĂ , poor man's VNC (except VNC is free). It is a neat trick anyway.
An even neater trick is if you have an isight, and you think someone is using your computer. Use isightcapture to take a picture of them (You'll have to download this).
Download a file
curl -O http://example.com/filename
If you install wget then you can use it as well (Rudix is probably the easiest way to get it for Mac OS X). Example:
wget http://example.com/filename
Sleep
osascript -e 'tell application "System Events"' -e 'sleep' -e 'end tell'
Remotely waking it is going to be a bit hard. Apple Remote Desktop can do it (if you are on the same subnet). Otherwise, good luck.
Finding out what is running
So the dock shows you what is running. You can get the same information by running the ps
command with the Aww
flags, which tells ps
to show all processes and their full path.
[Computer:~] james% ps -Aww
PID TT STATTIME COMMAND
1 ?? S<s 0:02.99 /sbin/launchd
23 ?? Ss 0:00.95 /sbin/dynamic_pager -F /private/var/vm/swapfile
27 ?? Ss 0:01.66 kextd
31 ?? Ss 0:28.50 /System/Library/PrivateFrameworks/DedicatedNetworkBuilds.framework/Resources/bfobserver
32 ?? Ss 0:00.06 /usr/sbin/KernelEventAgent
33 ?? Ss 0:05.80 /usr/sbin/mDNSResponder -launchdaemon
34 ?? Ss 0:05.17 /usr/sbin/netinfod -s local
35 ?? Ss 0:00.87 /usr/sbin/syslogd
37 ?? Ss 0:31.53 /usr/sbin/configd
38 ?? Ss 0:03.42 /usr/sbin/coreaudiod
...
This will show you lots of good information, like the process ID (PID). Using the PID, you can kill (force quit) a process (see below). The STAT column tells you what the process is doing, such as sleeping (good processes are very much like cats, they sleep an awful lot). It also tells how much time of the CPU the process has consumed. Good, bug free processes, will not use the CPU when you are not using it. As of this writing, Photoshop is still Carbon, so we still must forgive it.
To read the STAT column, look at the first character. It will be either I (idle), S (sleep), R (runnable), T (stopped), U (uninterruptible wait, waiting for some disk or network event-possibly hung, but not necessarily), or Z (zombie). If you see a Z, then you have a zombie process that is trolling your computer eating other processes. Just kidding. A zombie process is a process that was quit but it wont die. To get rid of it, you will have to restart the computer. Zombie processes aren't suppose to happen. I've actually had some computers not restart because the computer waits for the zombie to die, and it never does, so I had to hard restart it. I've also had some computers with zombies not boot up after restarting. So having a zombie could spell trouble. Then again, it may be nothing but a programmer bug.
Adding the j flag will show user type information:
[Computer:~] james% ps -Awwj
USER PID PPID PGID SESS JOBC STAT TT TIME COMMAND
root 1 0 1 2844e88 0 S<s ?? 0:03.00 /sbin/launchd
root 23 1 23 2844c60 0 Ss ?? 0:00.95 /sbin/dynamic_pager -F /private/var/vm/swapfile
root 27 1 27 2844b4c 0 Ss ?? 0:01.66 kextd
root 31 1 31 28438f8 0 Ss ?? 0:28.51 /System/Library/PrivateFrameworks/DedicatedNetworkBuilds.framework/Resources/bfobserver
root 32 1 32 28445e8 0 Ss ?? 0:00.06 /usr/sbin/KernelEventAgent
...
windowse 56 1 56 28437e4 0 Rs ?? 41:57.92 /System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Resources/WindowServer -daemon
root 61 37 37 28444d4 0 S ?? 0:02.16 /usr/sbin/blued
root 64 1 64 2843a0c 0 Ss ?? 4:41.96 /System/Library/CoreServices/coreservicesd
james 69 1 69 28436d0 0 Ss ?? 0:09.11 /System/Library/Frameworks/ApplicationServices.framework/Frameworks/ATS.framework/Support/ATSServer
james 70 1 70 28434a8 0 Ss ?? 0:05.07 /System/Library/CoreServices/loginwindow.app/Contents/MacOS/loginwindow console
...
Another method to find out what is running on your system is to use top
. It will show you a second by second snapshot of what is running, so you can get a vague idea how busy your machine is.
Processes: 72 total, 2 running, 70 sleeping... 269 threads16:18:21
Load Avg: 0.43, 0.31, 0.30 CPU usage: 7.6% user, 8.0% sys, 84.4% idle
SharedLibs: num = 241, resident = 36.6M code, 5.25M data, 5.83M LinkEdit
MemRegions: num = 10821, resident = 305M + 15.9M private, 153M shared
PhysMem: 233M wired, 473M active, 277M inactive, 984M used, 39.1M free
VM: 12.3G + 158M 330051(0) pageins, 265393(0) pageouts
PID COMMAND%CPU TIME #TH #PRTS #MREGS RPRVT RSHRD RSIZE VSIZE
5649 top 10.6% 0:08.43 1 18 20 624K 692K 1.04M 26.9M
5618 tcsh 0.0% 0:00.02 1 15 20 408K 976K 908K 31.1M
5600 tcsh 0.0% 0:00.04 1 15 20 408K 976K 912K 31.1M
5548 mdimport 0.0% 0:00.15 3 61 42 704K 2.81M 2.34M 38.9M
5522 mdimport 0.0% 0:00.57 4 66 106 1.29M 2.92M 3.66M 57.9M
5369 ping 0.0% 0:01.54 1 14 19 140K 648K 376K 26.8M
5355 iChatAgent 0.0% 0:00.52 3 70 68 1.34M 3.53M 11.6M 297M
5354 iChat 0.0% 0:01.13 6 243 252 7.25M 9.54M 31.3M 360M
...
Force quitting processes
You can force quit ("kill") a process using the pid (obtained with ps
or top
):
sudo kill 1
Or you can kill it by name:
sudo killall launchd
Or you can force kill it (SIGKILL) if polite kill (SIGTERM) doesn't work:
sudo kill -9 1
sudo killall -9 launchd
(BTW, killing launchd is a very bad idea.)
Editing text files from the command line
The easiest option to edit via command line is pico
(nano
in 10.4). It was written for non-programmers to use with the email reader pine
. So pico
shows you the available commands at the bottom of the terminal window and is fairly obvious (for a Terminal based editor).
A problem with pico
is that it will hard wrap lines. nano
does not have this problem. However, if resize the window bigger while using nano
it will hang (and take as much CPU as it can get away with). It does this in iTerm too, so it isn't a Terminal.app bug.
pico <filename>
nano <filename>
In 10.4, if you type pico
, it will open nano
for you. For some reason, I can't get out of the habit of typing pico
.
If you type pico
and then the name of a file that doesn't exist, pico
will create that file when you save. There is no way to open a new file (like the "File" -> "Open" menu). You have to exit and then type pico
again with a new filename.
The important functions in pico
are:
ctrl-o to save (it means write out, out being the significant word... don't ask me why)
ctrl-x to exit (it will ask if you want to save if you made changes and haven't saved)
ctrl-w to find (where being the significant word)
ctrl-y page up
ctrl-v page down
ctrl-k cut line(s)
ctrl-u uncut line(s)
ctrl-shift-6 start/stop mark (so you can cut many lines)
If you ever press ctrl-j
(which is dangerously close to ctrl-k
), it will "wrap" everything for you and I think it does a pretty miserable job, especially if it is code. Just press ctrl-u
right after to undo it.
Hardcore editing text files from the command line
If you are serious about being a hardcore command line person, you will want to learn vi
or emacs
. I'll just say that you should at least learn enough vi
to change, save, and exit a file, because visudo
is one command line utility that forces you to use vi
. Ok, you can configure it to use pico
, but learning vi
that hard. Well, if you really want to use pico
, check out the next section (set EDITOR to "/usr/bin/pico").
Edit a file with vi
:
vi <filename>
- To go to insert mode (so you can add more lines and type things like ":") just start typing (look for the text "- INSERT -" to appear at the bottom).
- To save: hit the
esc
key (takes you out of insert mode), then type ":w" - To save and quit: hit the
esc
key, then type ":wq" - To quit without saving: hit
the
esc key, then type ":q!"
Environment Variables
I remember when I first learned Unix there were these mysterious things called environment variables. I knew what a variable was from algebra (y=m*x anyone?), what why was it called environment? If you are into 3D graphics, you might think it has something to do with the background lighting. Well, as it turns out, the environment isn't that complex. If you open 2 terminal windows, and you change a variable in one, it wont affect the other window. That is because each has its own "environment" that is independent of each other.
What sort of variables are there? Well, anything you want. There are many built in variables, like your HOME, your PATH, and your EDITOR. There variables are set to the locations of your home folder and the paths of terminal commands.
This is how to change a variable if you are using BASH:
export VAR="new value"
And now TCSH:
setenv VAR "new value"
This is how to change the PATH variable in BASH (specify $PATH to keep the old values, which is important):
export PATH=/usr/local/mysql/bin:$PATH
And now TCSH:
setenv PATH /usr/local/mysql/bin:$PATH
If you want a variable to affect other terminal windows, you need to make it part of the shell startup sequence. You do that by editing the startup script for the shell. The following commands will add the text you need for you (very handy):
BASH:
echo 'export PATH=/usr/local/mysql/bin:$PATH' >> ~/.bash_profile
TCSH:
echo 'setenv PATH /usr/local/mysql/bin:$PATH' >> ~/.tcshrc
Replacing BBEdit's Multi-file search with the command line
To search for a word or phrase in a file or multiple files use grep
. Grep stands for "global regular expression print", which is a function of the "ed" command: g/re/p" where g is global, re represents the regular expression, and p is print. The name doesn't come from the sound cats make coughing up hairballs (which is more like "grk").
A regular expression is a formula for matching text that fits a pattern. The most obvious match is equals, that is "text" equals "text". With grep
, you cam perform complex system of wildcards matches, like "(T|t).x(T|t)" matches "text" (and many other combinations).
The really important thing to know is that certain characters have special regular expression meanings. When you use the special character, magical things will happen, and you suddenly find all kinds of text! For example, ".*" is a pattern that will find EVERYTHING! Another example is "..." which will find everything that has 3 characters!
So, this brings up a point. What if all you want is to find 3 real periods? You need to tell grep to not treat it like a special character, but as a character to find. Do this by "escaping" the character by placing a backslash in front of it, like this ".".
Here are the characters with regular expression meanings:
.[]?*+{}|
^ and $ also have special meanings if they come at the beginning or end of a word.
Any character following a also has special meanings (like "d" means digit), except for the special characters of course. Thus "." means period, "[" means "[", "?" means "?", etc.
Ironically, grep
requires -e in order to use full regular expressions. You can also use egrep
, which is the same thing as grep -e
.
Here is an example of looking for errors in the system.log file (using the case insensitive switch):
[Computer:/var/log] james% grep -i error system.log
Oct 7 14:41:53 Computer cp: error processing extended attributes: Operation not permitted
Oct 7 16:48:37 Computer kernel[0]: IOAudioStream[0x2b5df00]::clipIfNecessary() - Error: attempting to clip to a position more than one buffer ahead of last clip position (0,a83)->(1,1d5e).
-i specifies that the search is case insensitive (default is case sensitive).
Here is an example of searching for the text "NSWindow" recursively in the Apple Developer Examples but only in files that end with ".m".
[Computer:/Developer/Examples] james% grep -r --include="*.m" NSWindow *
Accessibility/AXCanvas/CanvasDoc.m:- (void)windowControllerDidLoadNib:(NSWindowController *)aController
Accessibility/AXCanvas/CanvasInspectorController.m:#pragma mark NSWindowController methods
Accessibility/AXCanvas/CanvasProxyTabView.m:- (NSWindow *)caxWindowAttribute {
AppKit/ClockControl/ClockControl.m: [notifCenter addObserver:self selector:callback name:NSWindowDidBecomeKeyNotification object: [self window]];
AppKit/ClockControl/ClockControl.m: [notifCenter addObserver:self selector:callback name:NSWindowDidResignKeyNotification object: [self window]];
...
The following example searches for NSWindow like before, but omits NSWindowController. It does this by taking the output of the first grep
and "piping" it to the grep -v
, which will remove lines with NSWindowController (see below for more about the pipe "|").
[Computer:/Developer/Examples] james% grep -r --include="*.m" NSWindow * | grep -v NSWindowController
Accessibility/AXCanvas/CanvasProxyTabView.m:- (NSWindow *)caxWindowAttribute {
AppKit/ClockControl/ClockControl.m: [notifCenter addObserver:self selector:callback name:NSWindowDidBecomeKeyNotification object: [self window]];
AppKit/ClockControl/ClockControl.m: [notifCenter addObserver:self selector:callback name:NSWindowDidResignKeyNotification object: [self window]];
...
This version uses the -w option to specify only the word NSWindow.
[Computer:/Developer/Examples] james% grep -r -w --include="*.m" NSWindow *
Accessibility/AXCanvas/CanvasProxyTabView.m:- (NSWindow *)caxWindowAttribute {
AppKit/HexInputServer/HexInputContext.m: NSWindow *window = [textField window];
AppKit/Sketch/SKTGridPanelController.m:- (void)setMainWindow:(NSWindow *)mainWindow {
AppKit/Sketch/SKTInspectorController.m:- (void)setMainWindow:(NSWindow *)mainWindow {
AppKit/TextEdit/Controller.m: NSWindow *window = [windows objectAtIndex:count];
AppKit/TextEdit/Document.m: NSWindow *window = [scrollView window];
AppKit/TextEdit/Document.m: if (same && updateIcon) [[self window] setTitleWithRepresentedFilename:@""]; // Workaround NSWindow optimization
AppKit/TextEdit/Document.m:- (NSWindow *)window {
This next grep
uses extended grep (egrep
, which is the same as grep -e
) to display files that have NSWindow or NSPanel.
[Computer:/Developer/Examples] james% egrep -r -w --include="*.m" "NS(Window|Panel)" *
Accessibility/AXCanvas/CanvasProxyTabView.m:- (NSWindow *)caxWindowAttribute {
AppKit/HexInputServer/HexInputContext.m: NSWindow *window = [textField window];
AppKit/HexInputServer/HexInputServer.m: NSPanel *panel = [[NSPanel allocWithZone:[self zone]] initWithContentRect:NSMakeRect(0, 0, 100, 40) styleMask:NSBorderlessWindowMask|NSUtilityWindowMask backing:NSBackingStoreBuffered defer:YES];
AppKit/Java/TextEdit/TextFinder.m:- (NSPanel *)findPanel {
AppKit/Java/TextEdit/TextFinder.m: return (NSPanel *)[findTextField window];
AppKit/Java/TextEdit/TextFinder.m: NSPanel *panel = [self findPanel];
AppKit/Sketch/SKTGridPanelController.m:- (void)setMainWindow:(NSWindow *)mainWindow {
Piping
Piping is when the output of one command is sent to another. So far, the output of every command we have tried so far is just printed to the terminal. By using the pipe character, "|", we can send that output to commands that take input. Here is an example of where that is useful.
A very simple case of piping is when we are looking to see if a particular process is running.
ps -Aww | grep -i <process name>
For example:
[Computer:~] james% ps -Aww | grep -i Safari
2121 ?? S 21:39.47 /Applications/Safari.app/Contents/MacOS/Safari -psn_0_18612225
5669 p1 R+ 0:00.00 grep -i Safari
Technically, there are 2 processes running with "Safari" as part of the command. One is Safari of course, the other is the very grep
command! That is because when ps
was running finding processes, so was grep
. So ps
showed us grep
and grep
showed itself because it had Safari as part of its command. Kinda like chicken and egg. Anyway, it will always be listed in the process listing, just like top
will be when running top
.
To remove it grep
from the output, use grep -v grep
. The "-v" flag says to exclude a pattern. So we are taking the output of the ps
, and print anything that has "Safari", then we take that output and print everything unless it has "grep". Like this:
ps -Aww | grep -i <process name> | grep -v grep
Which produces this:
[Computer:~] james% ps -Aww | grep -i Safari | grep -v grep
2121 ?? S 21:53.69 /Applications/Safari.app/Contents/MacOS/Safari -psn_0_18612225
That's better.
A radmind grep example
If you aren't a radmind administrator, skip this section. So lapply
gave an error that said that the folder "/Library/Application Support/Adobe/StartupScripts" could not be deleted because it was not empty. That means Radmind doesn't think the folder should exist, which happens if no transcripts contain the folder. Naturally, it would have contents if Radmind is told to put files in the folder. Radmind is like that, it wont create folders for you, even if you tell it to put files in the folder.
So we want to find out what transcripts specify files in that location, and we want to double check that at least one of them creates the folder (all of them should really). To do that, we search the files in "/var/radmind/client" for "/Library/Application Support/Adobe/StartupScripts".
First, we need to encode the path in such a way that grep
can actually find it. Replace the space with "" because that is how radmind transcripts encode spaces. Escape the backslash "" in "" since it is a grep
special character, so it becomes "". That results in "/Library/ApplicationSupport/Adobe/StartupScripts". We will put quotes around it because the shell interprets "" also. By putting quotes around it, you are telling shell just give it to grep unaltered.
So recursively search for the text and only print out transcript filenames:
grep -lr "/Library/ApplicationSupport/Adobe/StartupScripts" /var/radmind/client
If you run this command, you will see all the transcripts that specify files in that location. Now we want to find out if one of them actually creates the folder. Do this by leaving out the "-l" flag so grep
prints out every text match, like this:
grep -r "/Library/ApplicationSupport/Adobe/StartupScripts" /var/radmind/client
But then exclude everything that has the folder separator character after the word "StartupScripts", like this:
grep -v "StartupScripts/"
The line that creates the folder wont have the separator character after the name, so this should only print lines creating the folder:
grep -r "/Library/ApplicationSupport/Adobe/StartupScripts" /var/radmind/client | grep -v "StartupScripts/"
Considering we got the error we did, we probably wont see anything! That is how we would know it isn't specified in any transcript! This is an easy mistake to make when updating overloads. To fix it, go to the server and execute the first grep
(except search in "/var/radmind/transcript"), and add the directory to one or all of the transcripts.
What next?
I've pretty much covered everything the Finder can do, except burning CD's, and I've never done that from the command line, and I don't really feel like trying to figure it out (my ISP is currently down, and well, I didn't know all of this stuff off the top of my head ya know). And I'm not sure if it is possible from the command line to set the "Open with..." attribute of a file. I'm not sure that is possible.
So there you are! Who says we need a new Finder? You no longer need to use it!
Where to go next? How about learn everything there is to know about commands!
Published: 2008-01-01, last edited: 2020-05-11
Copyright © 2024 James Reynolds