Hashing out the hash command on Linux


When you type “hash” on a Linux system, you could get one of two very different responses depending on the shell you are using.

If you are using bash or a related shell such as ksh, you should see a list of the commands that you have used since your terminal session began, sometimes with a count of how many times each command was used. This can be more useful than using the history command if you just want to see your very recent command activity, but the hash command is not a single executable. Instead, it relies on your shell.

hash in bash

Here’s an example of the hash command run in bash:

$ hash
hits    command
   1    /usr/bin/who
   1    /usr/bin/vi
   1    /usr/bin/man
   2    /usr/bin/ls
   1    /usr/bin/clear
   3    /usr/bin/cat
   3    /usr/bin/ps

For bash, the hash command is a built-in. It’s not a separate executable, but a command built into the shell. Some commands—like pwd and echo—don’t get captured in the hash output. You’ll get the same result with this command:

$ builtin hash “$@”
hits    command
   1    /usr/bin/who
   1    /usr/bin/vi
   1    /usr/bin/man
   2    /usr/bin/ls
   1    /usr/bin/clear
   3    /usr/bin/cat
   3    /usr/bin/ps

I found the command shown above in the /usr/bin/hash script on my Fedora system. It’s an /usr/bin/sh script that looks like this:

$ cat /usr/bin/hash
#!/usr/bin/sh
builtin hash “$@”

If I run this script, I get no output:

$ /usr/bin/hash
$	<== no output

Why? Because the script starts a new shell, and no commands have been run in that shell so the hash command has nothing to report. Source the script using “.”, on the other hand, and you’ll get a very different response.

$ . /usr/bin/hash
Hits    command
   1    /usr/bin/who
   1    /usr/bin/vi
   1    /usr/bin/man
   2    /usr/bin/ls
   1    /usr/bin/clear
   3    /usr/bin/cat
   3    /usr/bin/ps

hash in ksh

For ksh, typing “hash” will also display a list of the commands you’ve run in the current session, but without the “Hits” column. Instead, it displays the commands used and the executables in a name=path format. This helps to clarify the reason why the shells are collecting this information in the first place. If the shell has to look down your search path to find the executables for all the commands you use, it helps to “remember” where those executables are located so that it doesn’t have to search your path each time you use the commands.

$ hash
bash=/usr/bin/bash
cat=/usr/bin/cat
column=/usr/bin/column
date=/usr/bin/date
ls=/usr/bin/ls
man=/usr/bin/man
ps=/usr/bin/ps

For ksh, hash appears to be an alias:

$ alias | grep hash
hash=’alias -t —‘

Running the command associated with the alias should yield the same output:

$ alias -t —
bash=/usr/bin/bash
cat=/usr/bin/cat
column=/usr/bin/column
date=/usr/bin/date
ls=/usr/bin/ls
man=/usr/bin/man
ps=/usr/bin/ps

hash in zsh

The hash command in some other shells, like zsh, will provide a very different response. Instead of reporting on the current shell’s command history, it will show you a lengthy list of commands and their file system locations. To see how long the list of remembered locations is, use a command like this:

shs@dragonfly ~ % hash | wc -l
2753

To view the list, you will probably want to pipe the command output to the more command.

shs@dragonfly ~ % hash | more
.keepme=/home/linuxbrew/.linuxbrew/bin/.keepme
7z=/usr/bin/7z
7za=/usr/bin/7za
AtomicParsley=/usr/bin/AtomicParsley
BoD_meeting=/home/shs/bin/BoD_meeting
EZscript=/home/shs/bin/EZscript
Mail=/usr/bin/Mail
ModemManager=/usr/sbin/ModemManager
NetworkManager=/usr/sbin/NetworkManager
VBoxClient=/usr/bin/VBoxClient
VBoxClient-all=/usr/bin/VBoxClient-all
VBoxControl=/usr/bin/VBoxControl

In this case, commands included in the output are not restricted to those you have run.

Notice that the shell is not just keeping track of system commands, but also records the locations of scripts you have added in your home directory. When you run a new script, it will be added to your hash output and be visible the next time you start your shell.

shs@dragonfly ~ % hash | grep shs | head -10
BoD_meeting=/home/shs/bin/BoD_meeting
EZscript=/home/shs/bin/EZscript
about=/home/shs/bin/about
append=/home/shs/bin/append
backups.log=/home/shs/bin/backups.log
bash.pg=/home/shs/bin/bash.pg
bigfile=/home/shs/bin/bigfile
bigfile2=/home/shs/bin/bigfile2
calcPower=/home/shs/bin/calcPower
newscript=/home/shs/bin/newscript

Wrap-Up

The hash command’s response depends on the shell you are using and how it maintains its references to commands you run and the executables on your system. The primary purpose in keeping track of commands is to speed response time by reducing the time required to locate them.

Join the Network World communities on Facebook and LinkedIn to comment on topics that are top of mind.

Copyright © 2022 IDG Communications, Inc.



Source link