Jaki jest cel polecenia skrótu?


116

Po uruchomieniu hashpokazuje ścieżkę wszystkich poleceń uruchomionych od czasu ostatniego resetowania skrótu ( 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

Według stron podręcznika hash ma na celu:

Narzędzie / usr / bin / hash wpływa na sposób, w jaki bieżące środowisko powłoki zapamiętuje lokalizację znalezionych narzędzi. W zależności od podanych argumentów dodaje lokalizacje narzędzi do swojej listy zapamiętanych lokalizacji lub czyści zawartość listy. Jeśli nie podano żadnych argumentów, raportuje zawartość listy. Ta -ropcja powoduje, że powłoka zapomina o wszystkich zapamiętanych lokalizacjach.

Narzędzia dostarczone jako wbudowane w powłokę nie są zgłaszane przez skrót.

Poza tym, ile razy wpisałem polecenie, nie widzę użyteczności hash.

Został nawet opisany w 15 najważniejszych poleceniach thegeekstuff.com

W jaki sposób jest hashużyteczny?

Odpowiedzi:


94

hashjest wbudowanym poleceniem bash. Tabela skrótów jest funkcją bash zapobiegającą wyszukiwaniu przy $PATHkażdym wpisaniu polecenia przez buforowanie wyników w pamięci. Tabela jest czyszczona w przypadku zdarzeń, które oczywiście unieważniają wyniki (takie jak modyfikowanie $PATH)

hashPolecenie jest po prostu jak na interakcję z tego systemu (na jakikolwiek powód czujesz trzeba).

Niektóre przypadki użycia:

  • Tak jak widziałeś, wypisuje, ile razy uderzyłeś, które polecenia, jeśli wpiszesz je bez argumentów. Może ci to powiedzieć, których poleceń używasz najczęściej.

  • Możesz go również użyć do zapamiętania plików wykonywalnych w niestandardowych lokalizacjach.

Przykład:

[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 ~]#

Co może być przydatne, jeśli masz tylko jeden plik wykonywalny w katalogu poza $PATHtym, który chcesz uruchomić, po prostu wpisz nazwę zamiast dołączać wszystko do tego katalogu (co byłoby efektem, gdybyś go dodał $PATH).

Jednak alias zwykle może to zrobić, a ponieważ modyfikujesz zachowanie bieżącej powłoki, nie jest ona mapowana w programach, które uruchamiasz. Dowiązanie symboliczne do pojedynczego pliku wykonywalnego jest tutaj prawdopodobnie preferowaną opcją. hashjest jednym ze sposobów na zrobienie tego.

  • Możesz go użyć do zapamiętania ścieżek plików. Jest to przydatne, jeśli nowy plik wykonywalny pojawia się we wcześniejszym PATHkatalogu lub przenosi się mvdo innego miejsca i chcesz zmusić bash do wyjścia i znalezienia go ponownie, zamiast ostatniego miejsca, w którym pamięta o znalezieniu.

Przykład:

[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 ~]#

cpPolecenie spowodowało nową wersję z lspliku wykonywalnego, aby pokazać się wcześniej w moim $PATH, ale nie wywoła czystkę tabeli hash. Kiedyś hash -dwybiórczo czyściłem wpis lsz tabeli skrótów. Bash został zmuszony do $PATHponownego przejrzenia, a kiedy to zrobił, znalazł go w nowszej lokalizacji (wcześniej w $ PATH niż wcześniej).

Możesz selektywnie wywoływać to zachowanie „znajdź nową lokalizację pliku wykonywalnego z $PATH”, jednak:

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

Powinieneś to po prostu zrobić, jeśli chcesz coś z tabeli skrótów i nie jesteś w 100% tym, co możesz wylogować, a następnie pomyślnie się zalogować lub chcesz zachować pewne modyfikacje, które wprowadziłeś w swojej powłoce.

Aby pozbyć się przestarzałych mapowań, możesz także zrobić hash -r(lub export PATH=$PATH), który skutecznie po prostu przeczyści całą tablicę skrótów bash.

Jest wiele takich małych sytuacji. Nie wiem, czy nazwałbym to jednym z „najbardziej użytecznych” poleceń, ale ma kilka przypadków użycia.


Zastanawiam się, skąd wzięła się nazwa „hash”. A co z np. „Pamięcią podręczną”? :)
Michael,

2
@ Michael Ponieważ hashpolecenie wewnętrznie używa tabeli skrótów do przechowywania mapowań. en.wikipedia.org/wiki/Hash_table
jlliagre

10
Należy zauważyć, że hashnie jest to bashspecyficzne, polecenie pochodzi z powłoki Bourne'a w SVR2 (choć funkcja wcześniejszych ścieżek poleceń pochodzi cshwcześniej) i znajduje się we wszystkich powłokach podobnych do Bourne'a i POSIX.
Stéphane Chazelas,

1
Zamiast export PATH=$PATHwyczyścić stół, hash -rpowinno wystarczyć.
ravron

1
Innym przypadkiem użycia jest instalacja drugiej kopii programu we wcześniejszej części ścieżki $ PATH. Musisz hash -ralbo dostaniesz starą wersję, ponieważ $ PATH się nie zmieniła, więc Bash nie zdaje sobie sprawy, że mógłby załadować ten sam program z wcześniejszego katalogu (o wyższym priorytecie). Szczegółowe informacje można znaleźć na stronie conda.pydata.org/docs/… .
John Zwinck,

37

Oto klasyczne, uproszczone użycie:

# 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.

Jak wspomniano tutaj, selektywną aktualizację tablicy skrótów można wywołać za pomocą jednego polecenia hash hello.
Ioannis Filippidis

@johntex: ok, zmieniono.
rici

Wyobraź sobie możliwość wystąpienia dziwnych błędów, zanim dowiesz się, że istnieje tabela skrótów! Czy istnieje lista okoliczności, w których tabela skrótów jest automatycznie odświeżana?
benjimin

@benji: nigdy nie jest automatycznie odświeżany (jako całość). Jeśli uruchomisz bash w trybie POSIX lub setopt -s checkhashjeśli plik wykonywalny skrótu dla polecenia już nie istnieje, pozycja skrótu dla tego polecenia zostanie zaktualizowana. Zauważ jednak, że każda sesja bash miała własną tablicę skrótów, więc zamknięcie sesji i rozpoczęcie nowej skutecznie opróżnia skrót. ( hash -rjest to łatwiejszy sposób.)
rici

$PATHWydaje się, że aktualizacja lub uruchomienie nowego terminalu bash wyczyścił tabelę.
benjimin

17

Oto przydatne zastosowanie hash:

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

Oznacza to: jeśli php nie znajduje się w ŚCIEŻCE, użyj

/usr/local/foobar/php/bin/

7

Tak, Bash Reference Manual mówi:

Pełne wyszukiwanie katalogów w $ PATH jest wykonywane tylko wtedy, gdy polecenia nie znaleziono w tabeli skrótów.

Ale możesz wyłączyć haszowanie za pomocą set +h:

-h - Zlokalizuj i zapamiętaj (hash) polecenia, które są wyszukiwane do wykonania. Opcja jest wyłączona domyślnie.

Próbować:

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

To samo dotyczy hash -r, hash NAMEetc

A „wykrywanie komenda” (jak to albo , że ) nie działa:

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

Możesz napisać coś takiego:

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

lub (dzięki @mikeserv) bez konieczności przypisywania nowych zmiennych lub wykonywania testów:

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

1
Jeśli old_optionschodzi o twoją sprawę - zwykle robię coś takiego: set -h -- "-${-:--}" "$@"; hash ...; set +h "$@"wszystko po prostu wpasowuje się automatycznie, bez konieczności przypisywania nowych zmiennych lub wykonywania jakichkolwiek testów.
mikeserv

5

Łatwe wykrywanie, czy polecenie jest dostępne:

CMD=gzip
if hash bzip2; then
    CMD=$_
fi
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.