You are currently browsing the daily archive for April 21, 2008.
The Tiger and Leopard releases of MacOS X include an implementation of BSD’s dummynet
. Dummynet is “a system facility that permits the control of traffic going through the various network interfaces“.
There are many uses for this feature. I use it as part of my website development to simulate a slow network connection. Many of the users of our websites are in developing countries with slow, dialup-speed, network connections. By using a couple of quick commands I can throttle my connection to the webserver down to similar speeds. As such, I can feel their pain even though I’m on a snazzy gigabit connection, two hops away from the webserver.
The following series of commands will slow my communications to and from the webserver down to 56K modem speeds. It only affects http connections (to any web server, not just mine). My other network connections – ssh, for example – operate with native network performance.
$ sudo ipfw add pipe 1 src-port http $ sudo ipfw add pipe 1 dst-port http $ sudo ipfw pipe 1 config bw 56kbit/s
Adam Knight’s Traffic Shaping in Mac OS X is a good starter tutorial.
Here is a brief look at the Linux commands, type
and hash
.
To start, I open a new terminal and check for the location of the foo
executable using the which
command. (foo
is a trivial shell script I concocted for illustrative examples in this posting.)
$ which foo /usr/local/bin/foo
which
tells me the location of the executable file in my $PATH
but that is not necessarily what will be executed when I call foo
on the command line. To learn that, I use the type
command.
$ type foo foo is /usr/local/bin/foo
type
reports how a word will be interpreted if used as command name. In this case, it is telling me that using foo
as a command will execute the file /usr/local/bin/foo
. That happens to be what which
also reported, but, as we will see in the following examples, that will not always be the case.
I can run the foo
command to print its release version.
$ foo --version foo release 1.0
Consider if I install a new foo, version 2.0, in my ~/bin
directory, leaving the 1.0 version in /usr/local/bin/foo
. I have positioned ~/bin
ahead of /usr/local/bin
in my $PATH
and the which
command confirms the new 2.0 version is found first.
$ which foo /home/crashingdaily/bin/foo
However, when I call for foo
to be executed it still executes the old 1.0 version.
$ foo --version foo release 1.0
Hmm, what’s going on? The which
command reported the first executable found in my path but type
will be more informative. It will tell us precisely what file, function, builtin, keyword or alias is associated with a given command name.
$ type foo foo is hashed (/usr/local/bin/foo)
This is reporting that the shell has saved the meaning of foo
in a hash table as /usr/local/bin/foo
(the 1.0 version). Caching the command in a hash table is an optimization that saves the shell from having to search $PATH every time. A given shell does this the first time a command is run in that shell instance. The hashed values survive for the life of the shell instance. Start a new shell, e.g. by opening a new terminal or invoking a subshell, and you start a new hash table for that shell process.
The hash table can also be manually manipulated to clear or set values. Enter the hash
command. This command is used to print and edit the shell’s command hash table.
The entire hash table can be cleared
$ hash -r
or you can delete a specific entry
$ hash -d foo
Having cleared the hash table, invoking foo
now calls the first in my path.
$ foo --version foo release 2.0
And this copy is now placed in the hash table.
$ type foo foo is hashed (/home/crashingdaily/foo)
I can also print that entry of the hash table to get its value. However, do not use this as a substitute for type
as it only deals with files. More on that shortly.
$ hash -t foo /home/crashingdaily/foo
As you might imagine, if I delete the executable whose value has been hashed,
$ rm /home/crashingdaily/foo
the command is not found when I attempt to use it,
$ foo --version -bash: /home/crashingdaily/bin/foo: No such file or directory
until I update the hash. I can clear the hash as before or I can explictly set the value like so
$ hash -p /usr/local/bin/foo foo
$ type foo foo is hashed (/usr/local/bin/foo)
$ foo --version foo release 1.0
Keep in mind that the hash table caches (and the hash
command reports) file and path names. It does not deal with keywords, functions, builtins or aliases which may be invoked by a command name. So, type
is the utility to use for learning what will execute when a command name is invoked.
To further illustrate type
usage, I will define a function named foo
.
$ function foo { echo 'hello world'; }
Because function names take precedence over file executables having the same name, invoking foo
executes the function instead of the shell script. Now, type
reports
$ type foo foo is a function foo () { echo 'hello world' }
and invoking the name gives us the expected function output.
$ foo hello world
Using type
with the -a
option reports all the known values of foo
$ type -a foo foo is a function foo () { echo 'hello world' } foo is /home/crashingdaily/bin/foo foo is /usr/local/bin/foo
In summary, use type
to learn what a given command name currently means to the shell – there could be more than one meaning. Use hash
to manipulate cached associations of command names with files (and be aware that the command name may be associated with a non-file that takes precedence).
Additional documentation for type
and hash
is availble via the help
command.
$ help type type: type [-afptP] name [name ...] For each NAME, indicate how it would be interpreted if used as a command name...
$ help hash hash: hash [-lr] [-p pathname] [-dt] [name ...] For each NAME, the full pathname of the command is determined and remembered....