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....
About these ads