hash 命令的目的是什么?

spu*_*der 129 bash history

如果您运行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
Run Code Online (Sandbox Code Playgroud)

根据手册页,哈希的目的是:

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

散列不报告作为 shell 内置程序提供的实用程序。

除了查看我输入了多少次命令之外,我看不到hash.

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

在哪些方面hash有用?

Bra*_*ley 106

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 ~]#
Run Code Online (Sandbox Code Playgroud)

如果您在$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 ~]#
Run Code Online (Sandbox Code Playgroud)

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 ~]#
Run Code Online (Sandbox Code Playgroud)

如果您想从哈希表中删除某些内容并且不是 100% 可以注销然后成功重新登录,或者您想保留对 shell 所做的一些修改,那么您通常只想这样做。

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

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

  • 需要注意的是,`hash` 不是`bash` 特定的,该命令起源于SVR2 中的Bourne shell(尽管命令的散列路径特性在此之前来自`csh`)并且在所有Bourne-like 和POSIX 外壳。 (14认同)
  • @Michael 因为`hash` 命令在内部使用哈希表来存储映射。http://en.wikipedia.org/wiki/Hash_table (4认同)
  • 而不是`export PATH=$PATH` 来清除表,`hash -r` 就足够了。 (3认同)

ric*_*ici 41

这是简化的经典用法:

# 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 $0

# 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.
Run Code Online (Sandbox Code Playgroud)


Gil*_*not 20

这是一个有用的用法hash

hash php 2> /dev/null || hash -p /usr/local/foobar/php/bin/php php 2> /dev/null
Run Code Online (Sandbox Code Playgroud)

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

/usr/local/foobar/php/bin/
Run Code Online (Sandbox Code Playgroud)


Evg*_*gin 8

是的,Bash 参考手册说:

仅当在哈希表中未找到该命令时,才会对 $PATH 中的目录执行完整搜索。

但是您可以使用以下命令禁用散列set +h

-h - 查找并记住(散列)命令,因为它们被查找以供执行。默认情况下启用此选项。

尝试:

set +h
hash # prints bash: hash: hashing disabled
echo $? # prints 1
Run Code Online (Sandbox Code Playgroud)

这同样适用于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
Run Code Online (Sandbox Code Playgroud)

你可以这样写:

old_options="$-"
set -h
hash ls >/dev/null 2>&1 || echo "Please install ls" >&2
[[ "$old_options" =~ "h" ]] || set +h
Run Code Online (Sandbox Code Playgroud)

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

set -h -- "-${-:--}" "$@"
hash ls >/dev/null 2>&1 || echo "Please install ls" >&2
set +h "$@"
Run Code Online (Sandbox Code Playgroud)


bra*_*blc 6

轻松检测命令是否可用:

CMD=gzip
if hash bzip2; then
    CMD=$_
fi
Run Code Online (Sandbox Code Playgroud)