如果运行hash,它将显示自上次重置哈希后(hash -r

[root@c04c ~]# hash
hash: hash table empty

[root@c04c ~]# whoami
root

[root@c04c ~]# hash
hits    command
   1    /usr/bin/whoami

[root@c04c ~]# whoami
root

[root@c04c ~]# hash
hits    command
   2    /usr/bin/whoami


手册页以来运行的所有命令的路径,哈希的目的是:


/ usr / bin / hash实用程序影响当前shell
环境记住所找到的实用程序位置的方式。
根据指定的参数,它添加了实用程序位置
到其记忆位置列表中,或清除列表中的
内容。如果未指定任何参数,它将
报告列表的内容。 -r选项会导致
shell忘记所有记住的位置。

shell内置提供的实用程序不会被
哈希报告。


除了看到我输入了多少次命令外,我看不到hash的实用程序。

它甚至出现在thegeekstuff.com的前15个有用命令中

hash有什么用处?

#1 楼

hash是bash内置命令。哈希表是bash的一项功能,该功能可防止每次键入命令时都通过将结果缓存在内存中来搜索$PATH。在明显使结果无效的事件上清除了该表(例如修改$PATH

hash命令就是您与该系统进行交互的方式(无论您出于何种原因而需要)。 >
一些用例:


就像您看到的那样,如果您不带任何参数键入,它将打印出您击中了哪个命令的次数。这可能会告诉您最常用的命令。
还可以使用它来记住非标准位置的可执行文件。

示例:

[root@policyServer ~]# hash -p /lol-wut/whoami whoami
[root@policyServer ~]# whoami
Not what you're thinking
[root@policyServer ~]# which whoami
/usr/bin/whoami
[root@policyServer ~]# /usr/bin/whoami
root
[root@policyServer ~]#


如果您要在$PATH之外的目录中只有一个可执行文件,这可能会很有用只需键入名称即可,而不要在该目录中包含所有内容(如果将其添加到$PATH会产生效果)。

别名通常也可以做到这一点,但是由于您正在修改当前shell的行为,它不会映射到您启动的程序中。到单独的可执行文件的符号链接可能是此处的首选。 hash是一种实现方法。


您可以使用它取消记住文件路径。如果新的可执行文件在较早的PATH目录中弹出或将mv转移到其他位置,并且您想强制bash再次找到它而不是它记住的最后一个位置,则此功能非常有用。

示例:

[root@policyServer ~]# hash
hits    command
   1    /bin/ls
[root@policyServer ~]# cp /bin/ls /lol-wut
[root@policyServer ~]# hash
hits    command
   1    /bin/cp
   1    /bin/ls
[root@policyServer ~]# hash -d ls
[root@policyServer ~]# ls
default.ldif  newDIT.ldif  notes.txt  users.ldif
[root@policyServer ~]# hash
hits    command
   1    /bin/cp
   1    /lol-wut/ls
[root@policyServer ~]#


cp命令导致新版本的ls可执行文件较早地出现在我的$PATH中,但没有触发哈希表的清除。我使用hash -d从哈希表中有选择地清除了ls的条目。然后Bash被迫再次浏览$PATH,当它出现时,它在较新的位置(比以前运行的位置更早在$ PATH中)找到了它。来自$PATH的可执行文件”的行为,但是:

[root@policyServer ~]# hash
hits    command
   1    /bin/ls
[root@policyServer ~]# hash ls
[root@policyServer ~]# hash
hits    command
   0    /lol-wut/ls
[root@policyServer ~]#


如果您希望从哈希表中获取某些内容而不是100%,则通常只想这样做您可以注销然后重新成功登录,或者想要保留对Shell所做的一些修改。

要摆脱陈旧的映射,还可以执行hash -r(或export PATH=$PATH),有效地只是清除bash的整个哈希表。

有很多这样的小情况。我不知道是否将其称为“最有用的”命令之一,但确实有一些用例。

评论


我想知道“哈希”这个名字的来源。那例如“缓存”呢? :)。

–迈克尔
13年8月8日在20:11



@Michael因为hash命令在内部使用哈希表来存储映射。 zh.wikipedia.org/wiki/Hash_table

– jlliagre
13年8月8日在20:39



应该注意的是,哈希不是bash特定的,命令起源于SVR2的Bourne shell(尽管命令的哈希路径之前是csh的功能),并且在所有类似Bourne和POSIX的shell中都可以找到。

–StéphaneChazelas
13年8月8日在21:34

代替使用export PATH = $ PATH来清除表,哈希-r应该足够。

– ravron
16年1月4日在18:52

另一个用例是在$ PATH的较早部分中安装程序的第二个副本。您需要对-r进行哈希处理,否则将获得旧版本,因为$ PATH不变,因此Bash并未意识到它可以从较早(优先级更高)的目录中加载相同的程序。有关详细信息,请参见conda.pydata.org/docs/…。

– John Zwinck
17年1月19日在4:26

#2 楼

这是简化的经典用法:

# My PATH contains /home/rici/bin as well as the Usual Suspects:
# (the real one has lots more)
$ echo $PATH
/home/rici/bin:/usr/local/bin:/usr/bin:/bin

# I've installed a program called hello in /usr/local/bin
$ $ cat /usr/local/bin/hello
#!/bin/bash

echo Hello, world. I live at q4312078q

# The program works.
$ hello
Hello, world. I live at /usr/local/bin/hello

# Now I want to create a better hello, just for me. I put it in
# my own bin directory, and according to my PATH, it should come first.
$ cp /usr/local/bin/hello ~/bin/hello

# So now I will try running it
$ hello
Hello, world. I live at /usr/local/bin/hello

# WTF? Oh, forgot to run hash.
# Tell bash to update where to look for hello
$ hash hello
$ hello
Hello, world. I live at /home/rici/bin/hello

# Ah, all is well.


评论


如此处所述,可以使用单个命令哈希问候调用哈希表的选择性更新。

–艾奥尼斯·菲利皮迪斯(Ioannis Filippidis)
2014年8月9日下午0:42

@johntex:好的,更改了。

–rici
2014年8月9日在6:10

在知道哈希表存在之前,想象一下潜在的奇怪错误!是否存在自动刷新哈希表的情况列表?

– Benjimin
19年6月28日在1:00

@benji:永远不会自动刷新(整体上)。如果在posix模式下运行bash或setopt -s checkhash并且命令的哈希可执行文件不再存在,则该命令的哈希条目将被更新。但是请注意,每个bash会话都有自己的哈希表,因此关闭会话并开始一个新的会话实际上会清空该哈希。 (哈希-r是更简单的方法。)

–rici
19年6月28日在1:47

更新$ PATH或启动新的bash终端,似乎都可以清除表。

– Benjimin
19年6月28日在6:52

#3 楼

这是hash的有用用法:

hash php 2> /dev/null || hash -p /usr/local/foobar/php/bin/php php 2> /dev/null


这意味着:如果php不在PATH中,则使用

/usr/local/foobar/php/bin/


#4 楼

是的,《 Bash参考手册》说:


仅当在哈希表中找不到命令时,才对$ PATH中的目录进行完全搜索。


,但是您可以使用set +h禁用散列:


-h-查找并记住(散列)命令以查找其执行。默认情况下启用此选项。


尝试:

set +h
hash # prints bash: hash: hashing disabled
echo $? # prints 1


hash -rhash NAME等也相同

“命令检测”(诸如此类)不起作用:

set -h
hash ls >/dev/null 2>&1 || echo "Please install ls" >&2 # prints nothing

set +h
hash ls >/dev/null 2>&1 || echo "Please install ls" >&2 # prints Please install ls


您可以编写如下内容:

old_options="$-"
set -h
hash ls >/dev/null 2>&1 || echo "Please install ls" >&2
[[ "$old_options" =~ "h" ]] || set +h


或(感谢@mikeserv)而不必分配任何新变量或进行任何测试:

set -h -- "-${-:--}" "$@"
hash ls >/dev/null 2>&1 || echo "Please install ls" >&2
set +h "$@"


评论


对于您的old_options事情-我通常会执行以下操作:set -h-“-$ {-:-}”“ $ @”;哈希...;设置+ h“ $ @”,这样就可以自动将它们全部放置到位,而无需分配任何新变量或进行任何测试或其他操作。

–mikeserv
15年7月29日在11:28



#5 楼

轻松检测命令是否可用:

CMD=gzip
if hash bzip2; then
    CMD=$_
fi