วัตถุประสงค์ของคำสั่งแฮชคืออะไร?


118

หากคุณเรียกใช้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

ตามหน้า man วัตถุประสงค์ของการแฮชคือ:

ยูทิลิตี / usr / bin / hash มีผลต่อวิธีที่สภาพแวดล้อมเชลล์ปัจจุบันจดจำตำแหน่งของยูทิลิตีที่พบ ขึ้นอยู่กับอาร์กิวเมนต์ที่ระบุจะเพิ่มตำแหน่งยูทิลิตี้ในรายการของตำแหน่งที่จดจำหรือลบล้างเนื้อหาของรายการ เมื่อไม่มีการระบุอาร์กิวเมนต์มันจะรายงานเนื้อหาของรายการ -rตัวเลือกที่เป็นสาเหตุของเปลือกจะลืมสถานที่จำได้ทั้งหมด

ยูทิลิตี้ที่ให้มาเป็นบิวด์อินกับเชลล์จะไม่ถูกรายงานโดยแฮช

อื่น ๆ hashกว่าเห็นว่าหลายครั้งที่ฉันได้ป้อนคำสั่งฉันไม่สามารถเห็นยูทิลิตี้

มันเป็นจุดเด่นในคำสั่งที่มีประโยชน์ 15 อันดับแรกของ thegeekstuff.com

ในสิ่งที่วิธีที่เป็นhashประโยชน์หรือไม่

คำตอบ:


97

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)

นามแฝงมักจะทำสิ่งนี้ได้เช่นกันแม้ว่าคุณจะแก้ไขพฤติกรรมของเชลล์ปัจจุบัน แต่ก็ไม่ได้ถูกแมปในโปรแกรมที่คุณเริ่มต้น symlink ไปที่ lone executable อาจเป็นตัวเลือกที่ดีกว่าที่นี่ 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จากตารางแฮช ทุบตีถูกบังคับให้ต้องมองผ่าน$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% ที่คุณสามารถออกจากระบบแล้วกลับมาใหม่ได้สำเร็จหรือคุณต้องการรักษาการปรับเปลี่ยนบางอย่างที่คุณทำกับเปลือกของคุณ

เพื่อกำจัดการแมปค้างคุณยังสามารถทำhash -r(หรือexport PATH=$PATH) ซึ่งมีประสิทธิภาพเพียงกำจัดตารางแฮชทั้งหมดของ bash

มีสถานการณ์เล็ก ๆ น้อย ๆ มากมายเช่นนั้น ฉันไม่รู้ว่าฉันจะเรียกมันว่าหนึ่งในคำสั่ง "มีประโยชน์มากที่สุด" แต่มันมีบางกรณีใช้


ฉันสงสัยว่าชื่อ 'แฮช' มาจากไหน แล้วเช่น "แคช" แล้วล่ะ :)
Michael

2
@Michael เนื่องจากhashคำสั่งภายในใช้ตารางแฮชเพื่อจัดเก็บการแมป en.wikipedia.org/wiki/Hash_table
jlliagre

10
ควรสังเกตว่าhashไม่bashเฉพาะเจาะจงคำสั่งที่เกิดขึ้นในเชลล์เป้าหมายใน SVR2 (แม้ว่าคุณลักษณะของเส้นทางการแฮชของคำสั่งมาcshก่อนหน้านี้) และพบได้ในเชลล์บอร์นและ POSIX ทั้งหมด
Stéphane Chazelas

1
แทนที่จะexport PATH=$PATHล้างตารางhash -rควรพอเพียง
ravron

1
กรณีใช้งานอื่นคือเมื่อติดตั้งสำเนาที่สองของโปรแกรมลงในส่วนก่อนหน้าของ $ PATH ของคุณ คุณต้องการhash -rหรือคุณจะได้รับเวอร์ชันเก่าเนื่องจาก $ PATH ไม่เปลี่ยนแปลงดังนั้น Bash จึงไม่ทราบว่ามันสามารถโหลดโปรแกรมเดียวกันจากไดเรกทอรีก่อนหน้า (ลำดับความสำคัญสูงกว่า) ดูรายละเอียดที่conda.pydata.org/docs/…
John Zwinck

37

นี่คือการใช้แบบดั้งเดิมที่เรียบง่าย:

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

ในฐานะที่เป็นข้อสังเกตที่นี่hash helloปรับปรุงเลือกของตารางแฮชสามารถถูกเรียกด้วยคำสั่งเดียว
Ioannis Filippidis

@johntex: ตกลงเปลี่ยนแล้ว
rici

ลองนึกภาพศักยภาพของข้อผิดพลาดแปลก ๆ ก่อนที่จะรู้ว่ามีตารางแฮชอยู่! มีรายการสถานการณ์เมื่อตารางแฮชได้รับการรีเฟรชโดยอัตโนมัติหรือไม่?
benjimin

@benji: มันจะไม่รีเฟรชโดยอัตโนมัติ (โดยรวม) หากคุณรัน bash ในโหมด posix หรือsetopt -s checkhashและปฏิบัติการแฮชสำหรับคำสั่งไม่มีอยู่อีกต่อไปรายการ hash สำหรับคำสั่งนั้นจะถูกอัพเดต แต่โปรดทราบว่าทุกเซสชันของ bash นั้นมีตารางแฮชของตัวเองดังนั้นให้ปิดเซสชันและเริ่มใหม่เพื่อลบแฮชอย่างมีประสิทธิภาพ ( hash -rเป็นวิธีที่ง่ายต่อการทำที่.)
RICI

การอัปเดต$PATHหรือเรียกใช้งานเทอร์มินัล bash ใหม่ทั้งคู่ดูเหมือนจะล้างตาราง
benjimin

17

นี่คือการใช้ประโยชน์ของ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/

8

ใช่คู่มืออ้างอิง Bashบอกว่า:

การค้นหาไดเร็กทอรีแบบเต็มใน $ PATH จะดำเนินการเฉพาะเมื่อไม่พบคำสั่งในตารางแฮช

แต่คุณสามารถปิดการใช้งาน hashing ด้วยset +h:

-h - ค้นหาและจดจำคำสั่ง (แฮช) เมื่อค้นหาการประมวลผล ตัวเลือกนี้เปิดใช้งานโดยค่าเริ่มต้น

ลอง:

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

เช่นเดียวสำหรับhash -r, hash 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 "$@"

1
สำหรับold_optionsสิ่งที่คุณ- ฉันมักจะทำสิ่งนี้: set -h -- "-${-:--}" "$@"; hash ...; set +h "$@"ดังนั้นมันทั้งหมดตกหลุมโดยอัตโนมัติโดยไม่ต้องกำหนดตัวแปรใหม่หรือทำการทดสอบใด ๆ หรืออะไรก็ตาม
mikeserv

5

ตรวจจับได้ง่ายว่ามีคำสั่งให้บริการหรือไม่:

CMD=gzip
if hash bzip2; then
    CMD=$_
fi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.