ฉันจะลบรายการที่ซ้ำกันใน. bash_history ของฉันเพื่อรักษาลำดับได้อย่างไร


60

ฉันสนุกกับการใช้control+rเพื่อค้นหาประวัติคำสั่งของฉันซ้ำ ๆ ฉันพบตัวเลือกที่ดีบางอย่างที่ฉันชอบใช้กับมัน:

# ignore duplicate commands, ignore commands starting with a space
export HISTCONTROL=erasedups:ignorespace

# keep the last 5000 entries
export HISTSIZE=5000

# append to the history instead of overwriting (good for multiple connections)
shopt -s histappend

ปัญหาเดียวสำหรับฉันคือการerasedupsลบรายการที่ซ้ำกันตามลำดับเท่านั้นดังนั้นด้วยคำสั่งสตริงนี้:

ls
cd ~
ls

lsคำสั่งจริงจะถูกบันทึกไว้เป็นครั้งที่สอง ฉันคิดเกี่ยวกับการทำงานเป็นระยะ ๆ ด้วย:

cat .bash_history | sort | uniq > temp.txt
mv temp.txt .bash_history

สิ่งนี้จะประสบความสำเร็จในการลบรายการที่ซ้ำกัน แต่น่าเสียดายที่คำสั่งจะไม่ถูกเก็บไว้ หากฉันไม่ได้sortไฟล์ก่อนฉันไม่เชื่อว่าuniqสามารถทำงานได้อย่างถูกต้อง

ฉันจะลบรายการที่ซ้ำกันใน. bash_history ของฉันเพื่อรักษาลำดับได้อย่างไร

สินเชื่อพิเศษ:

มีปัญหากับการเขียนทับ.bash_historyไฟล์ผ่านสคริปต์หรือไม่? ตัวอย่างเช่นหากคุณลบไฟล์บันทึก apache ฉันคิดว่าคุณจำเป็นต้องส่งสัญญาณ nohup / reset ด้วยkillเพื่อให้มันล้างมันเป็นการเชื่อมต่อกับไฟล์ หากเป็นกรณีของ.bash_historyไฟล์ฉันอาจใช้วิธีpsตรวจสอบและตรวจสอบให้แน่ใจว่าไม่มีเซสชันที่เชื่อมต่อก่อนที่สคริปต์การกรองจะทำงานหรือไม่


3
ลองใช้ignoredupsแทนerasedupsสักครู่แล้วดูว่ามันเหมาะกับคุณอย่างไร
jw013

1
ฉันไม่คิดว่าทุบตีถือตัวจัดการไฟล์ที่เปิดอยู่กับไฟล์ประวัติ - มันอ่าน / เขียนเมื่อมันต้องการดังนั้นจึงควร (หมายเหตุ - ควร - ฉันยังไม่ได้ทดสอบ) ควรปลอดภัยที่จะเขียนทับมันจากที่อื่น
D_Bye

1
ฉันเพิ่งเรียนรู้สิ่งใหม่ในประโยคที่ 1 ของคำถามของคุณ ดีมาก!
Ricardo

ฉันไม่พบหน้าคนสำหรับตัวเลือกทั้งหมดในhistoryคำสั่ง ฉันควรมองหาที่ไหน
Jonathan Hartley

ตัวเลือกประวัติอยู่ใน 'man bash' ค้นหาส่วน 'shell builtin command' จากนั้นเลือก 'history' ด้านล่าง
Jonathan Hartley

คำตอบ:


36

การเรียงลำดับประวัติ

คำสั่งนี้ใช้งานได้เหมือนsort|uniqแต่เก็บสายไว้

nl|sort -k 2|uniq -f 1|sort -n|cut -f 2

โดยพื้นฐานแล้วจะเติมตัวเลขของแต่ละบรรทัด หลังจากsort|uniq-ing ทุกบรรทัดจะเรียงกลับตามคำสั่งเดิม (ใช้ฟิลด์หมายเลขบรรทัด) และฟิลด์หมายเลขบรรทัดจะถูกลบออกจากบรรทัด

วิธีการแก้ปัญหานี้มีข้อบกพร่องที่ไม่ได้กำหนดซึ่งเป็นตัวแทนของชั้นเรียนของเส้นที่เท่ากันจะทำให้มันในการส่งออกและดังนั้นตำแหน่งของมันในการส่งออกสุดท้ายจะไม่ได้กำหนด อย่างไรก็ตามหากควรเลือกตัวแทนล่าสุดคุณสามารถsortป้อนข้อมูลด้วยปุ่มที่สอง:

nl|sort -k2 -k 1,1nr|uniq -f1|sort -n|cut -f2

การจัดการ. bash_history

สำหรับการอ่านและเขียนประวัติอีกครั้งคุณสามารถใช้history -aและhistory -wตามลำดับ


6
เวอร์ชันของตกแต่งเรียงลำดับ undecorateนำไปใช้กับเครื่องมือเชลล์ ดี
ire_and_curses

ด้วยความsortที่-rสวิทช์เสมอฝืนเรียงลำดับ แต่สิ่งนี้จะไม่ให้ผลลัพธ์ที่คุณมีในใจ sortพิจารณาทั้งสองเหตุการณ์lsที่เหมือนกันกับผลลัพธ์ที่แม้ว่าเมื่อย้อนกลับลำดับสุดท้ายจะขึ้นอยู่กับอัลกอริทึมการเรียงลำดับ แต่ดูการปรับปรุงของฉันสำหรับความคิดอื่น
artistoex

1
ในกรณีที่คุณไม่ต้องการแก้ไข. bash_history คุณสามารถใส่คำสั่งต่อไปนี้ใน. bashrc: alias history = 'history | sort -k2 -k 1,1nr | uniq -f 1 | sort -n '
นาธา

อะไรคือnlจุดเริ่มต้นของสายรหัสแต่ละ? ไม่ควรhistoryหรือ
อัล

1
@AL nl เพิ่มหมายเลขบรรทัด คำสั่งโดยรวมแก้ปัญหาทั่วไป: การลบรายการที่ซ้ำกันในขณะที่รักษาลำดับ อินพุตถูกอ่านจาก stdin
artistoex

48

ดังนั้นฉันกำลังมองหาสิ่งที่แน่นอนเหมือนกันหลังจากถูกซ้ำซ้อนโดยรำคาญและพบว่าถ้าฉันแก้ไข ~ / .bash_profile (Mac) ด้วย:

export HISTCONTROL=ignoreboth:erasedups

มันทำสิ่งที่คุณต้องการอย่างแน่นอนเพียง แต่รักษาคำสั่งล่าสุดเท่านั้น ignorebothเป็นจริงเช่นเดียวกับการทำignorespace:ignoredupsและที่erasedupsได้รับงานทำ

อย่างน้อยใน terminal Mac ของฉันกับทุบตีงานนี้สมบูรณ์แบบ พบว่าที่นี่ใน askubuntu.com


10
นี่ควรเป็นคำตอบที่ถูกต้อง
MitchBroadhead

ทดสอบบน Max OS X Yosemite และ Ubuntu 14_04
Ricardo

1
เห็นด้วยกับ @MitchBroadhead วิธีนี้จะช่วยแก้ปัญหาภายในทุบตีตัวเองโดยไม่มีงาน cron ภายนอก ทดสอบบน Ubuntu 17.04 และ 16.04 LTS
Georg Jung

ทำงานบน OpenBSD ด้วย มันจะลบ dups ของคำสั่งใด ๆ ที่ผนวกเข้ากับไฟล์ประวัติซึ่งใช้ได้สำหรับฉัน มันมีผลที่น่าสนใจในการทำให้ไฟล์ประวัติสั้นลงขณะที่ฉันป้อนคำสั่งที่มีอยู่เป็นรายการซ้ำมาก่อน ตอนนี้ฉันสามารถทำให้ไฟล์ประวัติของฉันสั้นลงได้สูงสุด
WeakPointer

1
สิ่งนี้จะละเว้นคำสั่งที่ต่อเนื่องกันเท่านั้น หากคุณสลับกันซ้ำ ๆ ระหว่างสองคำสั่งที่ได้รับประวัติทุบตีของคุณจะเต็มไปด้วยรายการซ้ำ
Dylanthepiguy

16

พบวิธีแก้ปัญหานี้ในป่าและทดสอบ:

awk '!x[$0]++'

ครั้งแรกที่เห็นค่าเฉพาะของบรรทัด ($ 0) ค่าของ x [$ 0] เป็นศูนย์
ค่าเป็นศูนย์จะกลับกับ!และกลายเป็นหนึ่ง
คำสั่งที่ประเมินค่าเป็นสาเหตุการกระทำเริ่มต้นซึ่งพิมพ์

ดังนั้นในครั้งแรกที่$0เห็นเฉพาะนั้นจะถูกพิมพ์

ทุกครั้งถัดไป (ซ้ำ) ค่าที่x[$0]ได้รับการ incrented
ค่าเมื่อตะกี้มันเป็นศูนย์และคำสั่งที่ประเมินเป็นศูนย์จะไม่พิมพ์

หากต้องการเก็บค่าซ้ำล่าสุดให้ย้อนกลับประวัติและใช้ awk เดียวกัน:

awk '!x[$0]++' ~/.bash_history                 # keep the first value repeated.

tac ~/.bash_history | awk '!x[$0]++' | tac     # keep the last.

ว้าว! นั่นเพิ่งได้ผล แต่มันก็เอาออกทั้งหมด แต่เกิดขึ้นครั้งแรกที่ฉันเดา ฉันย้อนกลับการเรียงลำดับของบรรทัดโดยใช้ Sublime Text ก่อนใช้งาน ตอนนี้ฉันจะย้อนกลับอีกครั้งเพื่อรับประวัติที่สะอาดโดยมีเหตุการณ์ซ้ำทั้งหมดที่เหลืออยู่ ขอขอบคุณ.
trss

ลองดูคำตอบของฉัน!
Ali Shakiba

ที่ดีสะอาดและคำตอบทั่วไป (ไม่ได้ จำกัด ประวัติศาสตร์กรณีการใช้งาน) โดยไม่เปิดตัว bazilion กระบวนการย่อย ;-)
JepZ

9

การขยายคำตอบของ Clayton:

tac $HISTFILE | awk '!x[$0]++' | tac | sponge $HISTFILE

tacย้อนกลับไฟล์ตรวจสอบให้แน่ใจว่าคุณได้ติดตั้งmoreutilsเพื่อให้คุณspongeพร้อมใช้งานหรือใช้ไฟล์ชั่วคราว


1
สำหรับผู้ใช้บน Mac ให้ใช้brew install coreutilsและสังเกตว่า GNU utils ทั้งหมดมีการเตรียมการgเพื่อหลีกเลี่ยงความสับสนกับคำสั่ง Mac ในตัวของ BSD (เช่น gsed คือ GNU ในขณะที่ sed เป็น BSD) gtacดังนั้นการใช้
tralston

ฉันต้องการประวัติ -c และ history -r เพื่อให้มันใช้ประวัติศาสตร์
drescherjm

4

สิ่งเหล่านี้จะทำให้บรรทัดที่ซ้ำกันล่าสุด:

ruby -i -e 'puts readlines.reverse.uniq.reverse' ~/.bash_history
tac ~/.bash_history | awk '!a[$0]++' | tac > t; mv t ~/.bash_history

เพื่อความชัดเจนฉันเข้าใจถูกต้องว่าคุณได้แสดงโซลูชันที่ยอดเยี่ยมสองรายการที่นี่และผู้ใช้ต้องการดำเนินการอย่างใดอย่างหนึ่งเท่านั้น ทั้งทับทิมหรือ Bash?
Jonathan Hartley

3

นี่เป็นโพสต์เก่า แต่เป็นปัญหาถาวรสำหรับผู้ใช้ที่ต้องการเปิดเทอร์มินัลหลายเครื่องและมีการซิงโครไนซ์ประวัติระหว่างหน้าต่าง แต่ไม่ได้ทำซ้ำ

วิธีแก้ปัญหาของฉันใน. bashrc:

shopt -s histappend
export HISTCONTROL=ignoreboth:erasedups
export PROMPT_COMMAND="history -n; history -w; history -c; history -r"
tac "$HISTFILE" | awk '!x[$0]++' > /tmp/tmpfile  &&
                tac /tmp/tmpfile > "$HISTFILE"
rm /tmp/tmpfile
  • ตัวเลือก histappend เพิ่มประวัติบัฟเฟอร์ในตอนท้ายของไฟล์ประวัติ ($ HISTFILE)
  • การละเว้นและการลบช่วยป้องกันไม่ให้มีการบันทึกรายการที่ซ้ำกันใน $ HISTFILE
  • คำสั่ง prompt อัพเดตแคชประวัติ
    • history -n อ่านบรรทัดทั้งหมดจาก $ HISTFILE ที่อาจเกิดขึ้นในเทอร์มินัลอื่นตั้งแต่การรับคืนล่าสุด
    • history -w เขียนบัฟเฟอร์ที่อัพเดตไปที่ $ HISTFILE
    • history -c เช็ดบัฟเฟอร์เพื่อไม่ให้มีการทำซ้ำเกิดขึ้น
    • history -r อ่าน $ HISTFILE อีกครั้งต่อท้ายบัฟเฟอร์ที่ว่างในขณะนี้
  • สคริปต์ awk เก็บการเกิดขึ้นครั้งแรกของแต่ละบรรทัดที่พบ tacย้อนกลับแล้วย้อนกลับเพื่อให้สามารถบันทึกได้ด้วยคำสั่งล่าสุดที่ยังคงเป็นประวัติล่าสุด
  • rm ไฟล์ / tmp

ทุกครั้งที่คุณเปิดเชลล์ใหม่ประวัติจะมีการลบคำตอบทั้งหมดและทุกครั้งที่คุณกดEnterปุ่มในหน้าต่างเชลล์ / เทอร์มินัลอื่นอัปเดตประวัตินี้จากไฟล์



หาก "ละเว้นทั้งสองและการลบถูกป้องกันไม่ให้มีการบันทึกข้อมูลสองชุด" ดังนั้นทำไมคุณต้องทำคำสั่ง "awk" เพื่อลบข้อมูลที่ซ้ำกันออกจากไฟล์ เป็นเพราะ "เพิกเฉยทั้งสองและลบออก" ป้องกันไม่ให้มีการบันทึกข้อมูลที่ซ้ำกันติดกันหรือไม่ ขออภัยที่จะอวดฉันแค่พยายามที่จะเข้าใจ
Jonathan Hartley

1
การลบเท่านั้นลบรายการที่ซ้ำกันติดกัน และคุณถูกต้องแล้วที่คำสั่ง awk ทำซ้ำคำสั่ง erasedupes ทำให้มันไม่จำเป็น
smilingfrog

ขอบคุณที่ทำให้ฉันชัดเจนว่าเกิดอะไรขึ้น
Jonathan Hartley

0

ในการบันทึกคำสั่งใหม่ทุกคำสั่งนั้นไม่ยุ่งยาก ก่อนอื่นคุณต้องเพิ่ม ~/.profileหรือคล้ายกัน:

HISTCONTROL=erasedups
PROMPT_COMMAND='history -w'

จากนั้นคุณต้องเพิ่ม~/.bash_logout:

history -a
history -w

คุณช่วยฉันเข้าใจหรือไม่ว่าทำไมเมื่อออกจากระบบคุณต้องผนวกประวัติที่ไม่ได้เขียนไว้ในไฟล์ประวัติก่อนที่จะเขียนไฟล์ประวัติทั้งหมดอีกครั้ง คุณไม่สามารถเขียนไฟล์ทั้งหมดโดยไม่ใช้ 'ผนวก' หรือไม่
Jonathan Hartley
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.