เก็บรักษาประวัติทุบตีในหน้าต่างเทอร์มินัลหลายบาน


526

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

ฉันต้องการประวัติที่:

  • จดจำทุกสิ่งจากทุกสถานี
  • สามารถเข้าถึงได้จากทุกเทอร์มินัล (เช่นถ้าฉันlsเป็นหนึ่งให้เปลี่ยนไปที่เทอร์มินัลที่ทำงานอยู่แล้วจากนั้นกดขึ้นlsแสดงขึ้น)
  • อย่าลืมคำสั่งหากมีช่องว่างที่ด้านหน้าของคำสั่ง

ฉันสามารถทำอะไรเพื่อให้ทุบตีทำงานได้มากกว่านี้


57
ฉันเห็นข้อดีของมัน แต่โดยส่วนตัวแล้วฉันจะเกลียดมันในเปลือกของฉัน ฉันมักจะเปิดแท็บ 3 หรือ 4 แท็บในเทอร์มินัลของฉันสำหรับการใช้งานที่เฉพาะเจาะจงมาก: หนึ่งสำหรับการเรียกใช้ 'ทำ', หนึ่งกับ vi, หนึ่งเพื่อเรียกใช้สิ่งต่าง ๆ , ฯลฯ ดังนั้นเมื่อฉันรวบรวม, ฉันไปที่แท็บ 1 'ขึ้นมาและอื่น ๆ นี่เป็นประโยชน์อย่างมากสำหรับฉัน ดังนั้นถ้าฉันไปที่แท็บ 'ทำ' ของฉันและกดและคำสั่ง grep สุ่มปรากฏขึ้นฉันจะโกรธมาก! แค่บันทึกส่วนตัว
axel_c

4
@axel_c นั่นเป็นความจริงที่เพียงพอ ฉันไม่สามารถนึกถึงวิธีที่ชาญฉลาดในการทำที่อาคารที่มีอยู่เท่านั้นเห็นประวัติของตัวเอง แต่คนใหม่ดูรายการคำสั่งที่แม่นยำตามลำดับเวลา
Oli

8
@Oli เขียนว่า "ฉันไม่สามารถนึกถึงวิธีที่ชาญฉลาดในการทำสิ่งที่เทอร์มินัลปัจจุบันเห็นเฉพาะประวัติของตัวเอง แต่รายการใหม่จะเห็นรายการคำสั่งที่แม่นยำตามลำดับเวลา" วิธีการเกี่ยวกับ export PROMPT_COMMAND="history -a; $PROMPT_COMMAND"(ไม่ได้พิจารณา): เชลล์ที่มีอยู่จะเพิ่มแต่ละคำสั่งในไฟล์ประวัติเพื่อให้เชลล์ใหม่เห็น แต่แสดงเฉพาะประวัติของตนเอง
Chris หน้า

2
คุณต้องการเก็บประวัติทั้งหมดแยกจากกันหรือรวมเข้ากับไฟล์ประวัติเดียวหรือไม่?
kbyrd

3
คำตอบสั้น ๆ คือ: มันไม่ได้มีไว้สำหรับนักพัฒนาทุบตี โซลูชั่นบนพื้นฐานของการล้างแล้วกลับอ่านประวัติศาสตร์อาจจะทำผลงาน แต่ระวังของShlemiel จิตรกร ในคำธรรมดา: จำนวนของการประมวลผลงานระหว่างแต่ละคำสั่งเป็นสัดส่วนกับขนาดประวัติ
Stéphane Gourichon

คำตอบ:


329

เพิ่มรายการต่อไปนี้ใน ~ / .bashrc

# Avoid duplicates
export HISTCONTROL=ignoredups:erasedups  
# When the shell exits, append to the history file instead of overwriting it
shopt -s histappend

# After each command, append to the history file and reread it
export PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND$'\n'}history -a; history -c; history -r"

20
ปัญหาของโซลูชัน PROMPT_COMMAND นี้คือตัวเลขสำหรับแต่ละรายการประวัติเปลี่ยนแปลงหลังจากแต่ละคำสั่ง :( ตัวอย่างเช่นถ้าคุณพิมพ์ประวัติและ 1) ls 2) rm จากนั้นคุณทำ 1 เพื่อทำซ้ำ 1 หมายเลขประวัติอาจเปลี่ยนแปลงและ อาจเรียกใช้คำสั่ง RM และ ...
คริสคิมป์

2
เมื่อฉันทำสิ่งนี้เทอร์มินัลที่เปิดอยู่แล้วอื่น ๆ จะไม่มีคำสั่งป้อนสุดท้ายเมื่อฉันกด 'ขึ้น' จนกระทั่งหลังจากฉันออกคำสั่งในเทอร์มินัลนั้น - เป็นสิ่งที่คาดหวังหรือไม่ ถ้าเป็นเช่นนั้นจะมีวิธีในการแก้ไขประวัติของเทอร์มินัลอื่นอย่างแท้จริงหรือไม่?
Suan

7
@Suan นี้ดูเหมือนจะถูกต้องกับฉันตามคำสั่ง ฉันพบว่าเราสามารถออกคำสั่ง null ได้ (เพียงกดปุ่ม Enter) เพื่อรับประวัติการอัปเดต
ปราชญ์

3
ที่จริงhistory -a( ... ) ไม่ก่อให้เกิดการซ้ำกันการลบตามนี้คำตอบของคำถามประวัติศาสตร์ทุบตี“ignoredups” และ“erasedups” การตั้งค่าความขัดแย้งที่มีประวัติที่พบบ่อยในเซสชัน คำตอบนี้ยังให้ลำดับของhistory -<option>คำสั่งที่ทำงานกับHISTCONTROL=ignoredups:erasedupsการตั้งค่า
Piotr Dobrogost

23
ไม่มีเหตุผลที่จะไม่เป็นและตัวแปร: คุณกำหนดไว้ในเพื่อที่พวกเขาจะได้รับการกำหนดไว้ในทุกเปลือก (แม้ในคนที่ไม่ใช่แบบโต้ตอบซึ่งยังสิ้นเปลือง) exportHISTCONTROLPROMPT_COMMAND.bashrc
dolmen

248

ดังนั้นนี่คือทั้งหมดที่เกี่ยวข้องกับประวัติศาสตร์ของฉัน.bashrc:

export HISTCONTROL=ignoredups:erasedups  # no duplicate entries
export HISTSIZE=100000                   # big big history
export HISTFILESIZE=100000               # big big history
shopt -s histappend                      # append to history, don't overwrite it

# Save and reload the history after each command finishes
export PROMPT_COMMAND="history -a; history -c; history -r; $PROMPT_COMMAND"

ทดสอบกับ bash 3.2.17 บน Mac OS X 10.5, ทุบตี 4.1.7 ใน 10.6


3
อืมมม .. นี่เป็นความสามารถในการฆ่าที่ใช้ $! 34 เนื่องจากหมายเลขคำสั่งจะเปลี่ยนไปทุก ๆ มีวิธีแก้ปัญหา @Davide @Schof @kch หรือไม่

5
การใช้งานนี้จะได้รับประวัติศาสตร์ที่ไม่มีที่สิ้นสุด: ทุบตีประวัติศาสตร์นิรันดร์ อย่างไรก็ตามนี่เป็นอภินันทนาการจากโค้ดด้านบนเนื่องจากจะไม่ถูกโหลดซ้ำโดยอัตโนมัติ

7
FYI การแก้ปัญหาที่กล่าวถึงในที่นี้ไม่สามารถแก้ไขปัญหาต่อไปนี้ได้ ฉันมีสองเชลล์ windows A และ B ในเชลล์ window A ฉันรันsleep 9999และ (โดยไม่ต้องรอให้ sleep เสร็จสิ้น) ใน shell window B ฉันต้องการเห็นsleep 9999ในประวัติทุบตี
pts

1
@pts ฉันก็ตั้งเป้าที่จะมีพฤติกรรมสด แต่แล้วฉันก็รู้ว่ามันสะดวกกว่าที่จะมีประวัติเฉพาะเทอร์มินัลซึ่งทำให้การทำงานต่าง ๆ ในเทอร์มินัลต่าง ๆ ง่ายขึ้น ฉันพบว่าสิ่งนี้มีประโยชน์มาก: stackoverflow.com/questions/338285/#answer-7449399จากนั้นฉันทำให้นามแฝงhrefของฉันเรียกตัวเองว่าจะรีเฟรชประวัติของเทอร์มินัลปัจจุบันของฉันทันทีและล้างไฟล์ประวัติในกระบวนการ เมื่อใดก็ตามที่ฉันเปิดเทอร์มินัลใหม่การล้างข้อมูล / การซิงค์นั้นจะถูกดำเนินการในไฟล์ bashrc ของฉันดังนั้นเทอร์มินัลใหม่จะมีประวัติล่าสุด ฉันกำลังใช้สิ่งนั้นพร้อมกับhistory -a
trusktr

6
ไม่มีเหตุผลที่exportทำให้ตัวแปร: คุณกำลังกำหนดไว้ใน.bashrcดังนั้นพวกเขาจะถูกกำหนดไว้ในทุก ๆ เชลล์ (แม้แต่ในที่ไม่มีการโต้ตอบซึ่งก็สิ้นเปลือง)
dolmen

118

นี่คือความพยายามของฉันในการแบ่งปันประวัติเซสชัน Bash การทำเช่นนี้จะช่วยให้สามารถแบ่งปันประวัติระหว่างเซสชันทุบตีในลักษณะที่ตัวนับประวัติไม่ได้ปะปนกันและการขยายประวัติ!numberจะทำงานได้เหมือนเดิม(มีข้อ จำกัด บางอย่าง)

ใช้ Bash เวอร์ชัน 4.1.5 ภายใต้ Ubuntu 10.04 LTS (Lucid Lynx)

HISTSIZE=9000
HISTFILESIZE=$HISTSIZE
HISTCONTROL=ignorespace:ignoredups

_bash_history_sync() {
    builtin history -a         #1
    HISTFILESIZE=$HISTSIZE     #2
    builtin history -c         #3
    builtin history -r         #4
}

history() {                  #5
    _bash_history_sync
    builtin history "$@"
}

PROMPT_COMMAND=_bash_history_sync

คำอธิบาย:

  1. ต่อท้ายบรรทัดที่เพิ่งป้อนไปที่$HISTFILE(ค่าเริ่มต้นคือ.bash_history) สิ่งนี้จะทำให้$HISTFILEเติบโตโดยหนึ่งบรรทัด

  2. การตั้งค่าตัวแปรพิเศษ$HISTFILESIZEให้กับค่าบางค่าจะทำให้ Bash ตัดปลาย$HISTFILEไม่เกิน$HISTFILESIZEบรรทัดโดยการลบรายการที่เก่าที่สุด

  3. ล้างประวัติของเซสชันที่ทำงานอยู่ $HISTSIZEนี้จะช่วยลดเคาน์เตอร์ประวัติศาสตร์ตามจำนวนของ

  4. อ่านเนื้อหาของ$HISTFILEและแทรกลงในประวัติเซสชันที่กำลังรันอยู่ $HISTFILEนี้จะยกเคาน์เตอร์ประวัติศาสตร์ตามจำนวนของสายใน โปรดทราบว่าการนับสายของไม่จำเป็นต้องเป็น$HISTFILE$HISTFILESIZE

  5. history()ฟังก์ชั่นแทนที่ประวัติศาสตร์ในตัวเพื่อให้แน่ใจว่าประวัติศาสตร์จะตรงก่อนที่มันจะปรากฏขึ้น นี่เป็นสิ่งจำเป็นสำหรับการขยายประวัติตามหมายเลข (เพิ่มเติมเกี่ยวกับเรื่องนี้ในภายหลัง)

คำอธิบายเพิ่มเติม:

  • ขั้นตอนที่ 1 ทำให้แน่ใจว่าคำสั่งจากเซสชันที่รันอยู่ในปัจจุบันจะถูกเขียนไปยังไฟล์ประวัติโกลบอล

  • ขั้นตอนที่ 4 รับรองว่าคำสั่งจากเซสชันอื่น ๆ จะถูกอ่านเข้าสู่ประวัติเซสชันปัจจุบัน

  • เนื่องจากขั้นตอนที่ 4 จะเพิ่มตัวนับประวัติเราจำเป็นต้องลดตัวนับในบางวิธี ทำในขั้นตอนที่ 3

  • ในขั้นตอนที่ 3 $HISTSIZEเคาน์เตอร์ประวัติศาสตร์จะลดลง ในขั้นตอนที่ 4 $HISTFILEเคาน์เตอร์ประวัติศาสตร์จะเพิ่มขึ้นจากจำนวนของสายใน ในขั้นตอนที่ 2 เราตรวจสอบให้แน่ใจว่าการนับบรรทัด$HISTFILEนั้นแน่นอน$HISTSIZE(ซึ่งหมายความว่า$HISTFILESIZEจะต้องเหมือนกับ$HISTSIZE)

เกี่ยวกับข้อ จำกัด ของการขยายประวัติ:

เมื่อใช้การขยายตัวประวัติศาสตร์ด้วยหมายเลขที่คุณควรเสมอมองขึ้นจำนวนทันทีก่อนที่จะใช้ นั่นหมายความว่าไม่มีการแสดงข้อความแจ้งการ bash ระหว่างค้นหาหมายเลขและใช้งาน ซึ่งมักจะหมายถึงไม่มีการป้อนและไม่มี ctrl + c

โดยทั่วไปเมื่อคุณมีเซสชัน Bash มากกว่าหนึ่งเซสชันจะไม่มีการรับประกันใด ๆ ว่าการขยายประวัติตามหมายเลขจะคงคุณค่าไว้ระหว่างการแสดงพร้อมท์ของ Bash สองรายการ เพราะเมื่อPROMPT_COMMANDมีการดำเนินการประวัติจากช่วง Bash อื่น ๆ ทั้งหมดจะรวมอยู่ในประวัติศาสตร์ของเซสชันปัจจุบัน หากเซสชัน bash อื่นมีคำสั่งใหม่หมายเลขประวัติของเซสชันปัจจุบันจะแตกต่างกัน

ฉันพบว่าข้อ จำกัด นี้สมเหตุสมผล ฉันต้องค้นหาตัวเลขทุกครั้งเพราะฉันจำหมายเลขประวัติโดยพลการไม่ได้

ฉันมักจะใช้การขยายประวัติตามหมายเลขเช่นนี้

$ history | grep something #note number
$ !number

ฉันแนะนำให้ใช้ตัวเลือก Bash ต่อไปนี้

## reedit a history substitution line if it failed
shopt -s histreedit
## edit a recalled history line before executing
shopt -s histverify

ข้อผิดพลาดที่แปลก:

การรันคำสั่ง history ไปยังสิ่งใดจะส่งผลให้คำสั่งนั้นถูกแสดงรายการในประวัติสองครั้ง ตัวอย่างเช่น:

$ history | head
$ history | tail
$ history | grep foo
$ history | true
$ history | false

ทั้งหมดจะถูกระบุไว้ในประวัติศาสตร์สองครั้ง ฉันมีความคิดว่าทำไมไม่มี.

แนวคิดสำหรับการปรับปรุง:

  • ปรับเปลี่ยนฟังก์ชั่น_bash_history_sync()เพื่อไม่ให้ทำงานทุกครั้ง ตัวอย่างเช่นไม่ควรดำเนินการหลังจากCTRL+Cที่แจ้งให้ ฉันมักจะใช้CTRL+Cเพื่อละทิ้งบรรทัดคำสั่งยาวเมื่อฉันตัดสินใจว่าฉันไม่ต้องการรันบรรทัดนั้น บางครั้งฉันต้องใช้CTRL+Cเพื่อหยุดสคริปต์ Bash complete

  • คำสั่งจากเซสชันปัจจุบันควรเป็นคำล่าสุดในประวัติของเซสชันปัจจุบันเสมอ สิ่งนี้จะมีผลข้างเคียงที่หมายเลขประวัติที่กำหนดจะเก็บค่าสำหรับรายการประวัติจากเซสชันนี้


1
ทำไมไม่ "history -n" (โหลดบรรทัดที่ยังไม่ได้โหลด) แทน "history -c; history -r"
เกรแฮม

@ Graham: ฉันไม่ต้องการที่จะใช้history -nเพราะมันเลอะเคาน์เตอร์ประวัติศาสตร์ นอกจากนี้ฉันพบว่าhistory -nไม่น่าเชื่อถือเกินไป
Lesmana

1
ข้อเสียอย่างหนึ่ง: โดยทั่วไปคำสั่งที่มีสตริงหลายบรรทัดจะยังคงอยู่ในเซสชันปัจจุบัน ด้วยเคล็ดลับนี้พวกเขาจะแบ่งออกเป็นแต่ละบรรทัดทันที การใช้ -n สำหรับ -c -r ไม่ช่วยไม่ได้ทั้ง cmdhist หรือ lithist ฉันไม่คิดว่าจะมีวิธีแก้ปัญหาในจุดนี้
Jo Liss

24
หลังจากลองใช้งานมาซักพักแล้วฉันก็พบว่าการใช้งานเพียงอย่างเดียวhistory -aโดยไม่ต้องมี-cและ-rใช้งานได้ดีกว่า (แม้ว่าไม่ใช่คำถามที่ถาม) หมายความว่าคำสั่งที่คุณเรียกใช้จะพร้อมใช้งานทันทีในเชลล์ใหม่แม้กระทั่งก่อนที่จะออกจากเชลล์ปัจจุบัน แต่ไม่ใช่ในเชลล์ที่รันอยู่พร้อมกัน วิธีนี้ Arrow-Up ยังคงเลือกคำสั่งที่รันล่าสุดของเซสชันปัจจุบันเสมอซึ่งฉันพบว่าสับสนน้อยกว่ามาก
Jo Liss

คำตอบที่ดีเด่นอย่างนี้ทำงานได้อย่างน่าเชื่อถือซึ่งแตกต่างจาก "ประวัติศาสตร์ -a; history -n" ทั่วไปมากขึ้น
RichVel

42

ฉันไม่ทราบวิธีการใด ๆ bashที่ใช้ zshแต่มันเป็นหนึ่งในคุณสมบัติที่นิยมมากที่สุดของ
โดยส่วนตัวฉันชอบzshมากกว่าbashดังนั้นฉันแนะนำให้ลอง

นี่คือส่วนหนึ่งของฉัน.zshrcที่เกี่ยวข้องกับประวัติศาสตร์:

SAVEHIST=10000 # Number of entries
HISTSIZE=10000
HISTFILE=~/.zsh/history # File
setopt APPEND_HISTORY # Don't erase history
setopt EXTENDED_HISTORY # Add additional data to history like timestamp
setopt INC_APPEND_HISTORY # Add immediately
setopt HIST_FIND_NO_DUPS # Don't show duplicates in search
setopt HIST_IGNORE_SPACE # Don't preserve spaces. You may want to turn it off
setopt NO_HIST_BEEP # Don't beep
setopt SHARE_HISTORY # Share history between session/terminals

1
JFTR ชื่อกรณีตายและขีดจะถูกละเลย
Pablo A

16

ในการทำเช่นนี้คุณจะต้องเพิ่มสองบรรทัดใน~/.bashrc:

shopt -s histappend
PROMPT_COMMAND="history -a;history -c;history -r;$PROMPT_COMMAND"

จากman bash:

หากมีการเปิดใช้งานตัวเลือกเชลล์ histappend (ดูคำอธิบายของ shopt ภายใต้คำสั่ง SHELL BUILTIN คำสั่งด้านล่าง) บรรทัดจะผนวกเข้ากับไฟล์ประวัติมิฉะนั้นไฟล์ประวัติจะถูกเขียนทับ


10

คุณสามารถแก้ไขพรอมต์ BASH ของคุณเพื่อเรียกใช้ "history -a" และ "history -r" ที่ Muerr แนะนำ:

savePS1=$PS1

(ในกรณีที่คุณทำสิ่งที่ไม่แน่นอนซึ่งเกือบจะรับประกัน)

PS1=$savePS1`history -a;history -r`

(โปรดทราบว่าสิ่งเหล่านี้เป็นเครื่องหมายขีดหลังพวกเขาจะเรียกใช้ประวัติ -a และประวัติ -r ในทุก ๆ พรอมต์เนื่องจากข้อความเหล่านั้นไม่ส่งข้อความใด ๆ ข้อความแจ้งเตือนของคุณจะไม่เปลี่ยนแปลง

เมื่อคุณตั้งค่าตัวแปร PS1 ตามที่คุณต้องการแล้วให้ตั้งค่าตัวแปรถาวรในไฟล์ ~ / .bashrc ของคุณ

หากคุณต้องการกลับไปที่พรอมต์ดั้งเดิมของคุณขณะทำการทดสอบให้ทำ:

PS1=$savePS1

ฉันได้ทำการทดสอบขั้นพื้นฐานเกี่ยวกับเรื่องนี้เพื่อให้แน่ใจว่ามันเป็นงาน แต่ไม่สามารถพูดกับผลข้างเคียงใด ๆ จากการทำงานhistory -a;history -rในทุก ๆ ครั้ง


2
โซลูชันของ kch ทำงานได้ดีกว่าของฉัน ตอนนี้ฉันใช้โซลูชันของเขาใน. bashrc ของฉัน

9

หากคุณต้องการโซลูชันการซิงโครไนซ์ประวัติ bash หรือ zsh ซึ่งแก้ไขปัญหาด้านล่างด้วยให้ดูที่http://ptspts.blogspot.com/2011/03/how-to-automatically-synchronize-shell.html

ปัญหามีดังต่อไปนี้: ฉันมี shell windows A และ B สองตัวใน shell window A ฉันรันsleep 9999และ (โดยไม่ต้องรอให้ sleep เสร็จสิ้น) ใน shell window B ฉันต้องการเห็นsleep 9999ในประวัติทุบตี

เหตุผลที่โซลูชันอื่น ๆ ส่วนใหญ่ที่นี่จะไม่แก้ปัญหานี้ก็คือพวกเขากำลังเขียนการเปลี่ยนแปลงประวัติไปยังไฟล์ประวัติโดยใช้PROMPT_COMMANDหรือPS1ทั้งสองอย่างนี้กำลังดำเนินการช้าเกินไปหลังจากที่sleep 9999คำสั่งเสร็จสิ้น


1
นี่เป็นทางออกที่ดี แต่ฉันได้คำถามสองสามข้อ 1. ฉันสามารถใช้ไฟล์. bash_history ดั้งเดิมฉันไม่ต้องการให้มีไฟล์ประวัติ bash อื่นอยู่ใน $ HOME ของฉัน 2. คุณควรพิจารณาตั้งค่า repo github สำหรับสิ่งนี้
weynhamz

ดูเหมือนว่า debug hook จะขัดแย้งกับ bashdb ผลลัพธ์ที่ตามมาทุกครั้งที่ฉันเริ่มเซสชัน bash `` `ตัวแก้จุดบกพร่อง bash, bashdb, ปล่อย 4.2-0.8 ลิขสิทธิ์ 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011, 2011 Rocky Bernstein ซอฟต์แวร์นี้เป็นซอฟต์แวร์ฟรีที่ครอบคลุมโดยใบอนุญาตสาธารณะทั่วไปของ GNU และยินดีต้อนรับ เปลี่ยนแปลงและ / หรือแจกจ่ายสำเนาของมันภายใต้เงื่อนไขบางประการ ** ข้อผิดพลาดการดีบักภายใน _Dbg_is_file (): อาร์กิวเมนต์ไฟล์ทุบตี null: _Dbg_filenames [$ fullname]: ตัวห้อยอาร์เรย์ที่ไม่ถูกต้อง `` `
weynhamz

@Techlive Zheng: 1. .bash_history ดั้งเดิมไม่ได้รับการสนับสนุนโดยเจตนาเนื่องจาก. merged_bash_history ใช้รูปแบบไฟล์ที่แตกต่างกันดังนั้นในกรณีที่ .merged_bash_history ล้มเหลวในการโหลดอย่างถูกต้อง ความทนทานโดยการออกแบบจะถูกเก็บไว้ตามที่เป็นอยู่ 2. repo GitHub เป็นความคิดที่ดีโดยทั่วไป แต่ฉันไม่มีเวลาที่จะดูแลโครงการนี้ดังนั้นฉันไม่ได้ทำมัน - ใช่มันขัดแย้งกับ bashdb และไม่มีวิธีแก้ปัญหาง่าย ๆ (พวกเขาใช้ hooks ตัวเดียวกัน) ฉันไม่ได้วางแผนที่จะแก้ไข แต่ฉันยอมรับการแก้ไข
pts

โอเคขอบคุณ. ฉันได้มาด้วยความเรียบง่ายและมีน้ำใจมากขึ้น
weynhamz

@TechliveZheng: คุณจะแบ่งปันทางออกที่ง่ายและดีกว่าของคุณกับเราเพื่อให้เราทุกคนสามารถเรียนรู้จากมันได้หรือไม่ (ถ้าเป็นเช่นนั้นโปรดเพิ่มคำตอบให้กับคำถาม)
pts

8

คุณสามารถใช้history -aผนวกประวัติของเซสชันปัจจุบันเข้ากับ histfile จากนั้นใช้history -rบนเทอร์มินัลอื่นเพื่ออ่าน histfile 


8

ใช่แล้วในที่สุดสิ่งนี้ทำให้ฉันรำคาญที่จะหาทางออกที่เหมาะสม:

# Write history after each command
_bash_history_append() {
    builtin history -a
}
PROMPT_COMMAND="_bash_history_append; $PROMPT_COMMAND"

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

make
ls -lh target/*.foo
scp target/artifact.foo vm:~/

(ตัวอย่างประยุกต์)

และในอีก:

pv ~/test.data | nc vm:5000 >> output
less output
mv output output.backup1

ไม่มีทางที่ฉันต้องการแบ่งปันคำสั่ง


1
เหตุผลที่คุณจะโหลดประวัติหลังจากทุกคำสั่งก็คือมันเป็นพฤติกรรมที่ต้องการโดยคำถาม (และสิ่งนี้ไม่ได้ตอบคำถามตามที่วางไว้)
Michael Homer

2
@MichaelHomer จุดประสงค์ รู้สึกอิสระที่จะลงคะแนนดังนั้นคำตอบอยู่ที่ด้านล่าง แต่ฉันจะชอล์กนี้ถึง OP ไม่ทราบว่าพฤติกรรมที่ร้องขอจะไม่ดีและความจริงที่ว่านี้เป็นคำถามที่ googlable มาก
Yarek T

3
Op ที่นี่ใช่นั่นคือการประนีประนอมอย่างเป็นธรรม การร้องเรียนหลักของฉันคือการที่ฉันสูญเสียประวัติศาสตร์ สิ่งนี้ควรหยุดสิ่งนั้นแม้ว่าจะไม่ได้หมายความว่าจะมีการอัปเดตทันใจข้ามเซสชันพร้อมกัน
Oli

7

นี่คือทางเลือกที่ฉันใช้ มันยุ่งยาก แต่ก็แก้ปัญหาที่ @axel_c พูดถึงซึ่งบางครั้งคุณอาจต้องการมีอินสแตนซ์ประวัติแยกต่างหากในแต่ละเทอร์มินัล (หนึ่งรายการสำหรับทำหนึ่งรายการสำหรับตรวจสอบหนึ่งสำหรับ vim ฯลฯ )

ฉันเก็บไฟล์ประวัติต่อท้ายแยกต่างหากที่ฉันอัปเดตอยู่ตลอดเวลา ฉันได้แมปต่อไปนี้เพื่อฮอต:

history | grep -v history >> ~/master_history.txt

ข้อมูลนี้จะผนวกประวัติทั้งหมดจากเทอร์มินัลปัจจุบันไปยังไฟล์ชื่อ master_history.txt ใน dir บ้านของคุณ

ฉันยังมีปุ่มลัดแยกต่างหากเพื่อค้นหาไฟล์ประวัติต้นแบบ:

cat /home/toby/master_history.txt | grep -i

ฉันใช้แมว grep เพราะมันปล่อยเคอร์เซอร์ไว้ท้ายสุดเพื่อเข้าสู่ regex ของฉัน วิธีที่น่าเกลียดน้อยกว่าในการทำเช่นนี้คือการเพิ่มสคริปต์ลงในพา ธ ของคุณเพื่อทำงานเหล่านี้ให้สำเร็จ แต่ปุ่มลัดทำงานเพื่อจุดประสงค์ของฉัน ฉันยังจะดึงประวัติลงจากโฮสต์อื่นที่ฉันได้ทำงานเป็นระยะ ๆ และผนวกประวัตินั้นไปยังไฟล์ master_history.txt ของฉัน

มันดีเสมอที่จะสามารถค้นหาได้อย่างรวดเร็วและพบว่า regex ยุ่งยากที่คุณใช้หรือว่า perl หนึ่งซับที่แปลกประหลาดที่คุณสร้างขึ้นเมื่อ 7 เดือนที่แล้ว


6

ฉันสามารถเสนอการแก้ไขสำหรับสิ่งสุดท้าย: ตรวจสอบให้แน่ใจว่าตัวแปร env HISTCONTROL ไม่ได้ระบุ "ignorespace" (หรือ "ignboth")

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


6

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

หากคุณพิมพ์ 'ประวัติ' อย่างชัดเจนหรือถ้าคุณเปิดหน้าต่างใหม่คุณจะได้รับประวัติจากหน้าต่างก่อนหน้าทั้งหมด

นอกจากนี้ฉันใช้กลยุทธ์นี้เพื่อเก็บคำสั่งทุกคำที่เคยพิมพ์บนเครื่องของฉัน

# Consistent and forever bash history
HISTSIZE=100000
HISTFILESIZE=$HISTSIZE
HISTCONTROL=ignorespace:ignoredups

_bash_history_sync() {
  builtin history -a         #1
  HISTFILESIZE=$HISTSIZE     #2
}

_bash_history_sync_and_reload() {
  builtin history -a         #1
  HISTFILESIZE=$HISTSIZE     #2
  builtin history -c         #3
  builtin history -r         #4
}

history() {                  #5
  _bash_history_sync_and_reload
  builtin history "$@"
}

export HISTTIMEFORMAT="%y/%m/%d %H:%M:%S   "
PROMPT_COMMAND='history 1 >> ${HOME}/.bash_eternal_history'
PROMPT_COMMAND=_bash_history_sync;$PROMPT_COMMAND

5

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

# Convert /dev/nnn/X or /dev/nnnX to "nnnX"
HISTSUFFIX=`tty | sed 's/\///g;s/^dev//g'`
# History file is now .bash_history_pts0
HISTFILE=".bash_history_$HISTSUFFIX"
HISTTIMEFORMAT="%y-%m-%d %H:%M:%S "
HISTCONTROL=ignoredups:ignorespace
shopt -s histappend
HISTSIZE=1000
HISTFILESIZE=5000

ประวัติตอนนี้ดูเหมือนว่า:

user@host:~# test 123
user@host:~# test 5451
user@host:~# history
1  15-08-11 10:09:58 test 123
2  15-08-11 10:10:00 test 5451
3  15-08-11 10:10:02 history

ด้วยไฟล์ที่ดูเหมือนว่า:

user@host:~# ls -la .bash*
-rw------- 1 root root  4275 Aug 11 09:42 .bash_history_pts0
-rw------- 1 root root    75 Aug 11 09:49 .bash_history_pts1
-rw-r--r-- 1 root root  3120 Aug 11 10:09 .bashrc

3

ที่นี่ฉันจะชี้ปัญหาหนึ่งกับ

export PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND$'\n'}history -a; history -c; history -r"

และ

PROMPT_COMMAND="$PROMPT_COMMAND;history -a; history -n"

หากคุณเรียกใช้ซอร์ส ~ / .bashrc $ PROMPT_COMMAND จะเป็นเช่นนั้น

"history -a; history -c; history -r history -a; history -c; history -r"

และ

"history -a; history -n history -a; history -n"

การทำซ้ำนี้เกิดขึ้นทุกครั้งที่คุณเรียกใช้ 'source ~ / .bashrc' คุณสามารถตรวจสอบ PROMPT_COMMAND หลังจากแต่ละครั้งที่คุณเรียกใช้ 'source ~ / .bashrc' โดยเรียกใช้ 'echo $ PROMPT_COMMAND'

คุณสามารถเห็นคำสั่งบางคำสั่งเสียหาย: "history -n history -a" แต่ข่าวดีก็คือมันยังใช้งานได้เพราะชิ้นส่วนอื่นยังคงเรียงลำดับคำสั่งที่ถูกต้อง (เพียงแค่มีค่าใช้จ่ายเพิ่มเติมเนื่องจากการดำเนินการคำสั่งซ้ำ ๆ และไม่สะอาด)

ส่วนตัวฉันใช้รุ่นง่าย ๆ ต่อไปนี้:

shopt -s histappend
PROMPT_COMMAND="history -a; history -c; history -r"

ซึ่งมีฟังก์ชันการทำงานส่วนใหญ่ในขณะที่ไม่มีปัญหาดังกล่าวข้างต้น

อีกจุดที่ต้องทำคือไม่มีความมหัศจรรย์อะไรเลย PROMPT_COMMAND เป็นเพียงตัวแปรสภาพแวดล้อมทุบตีธรรมดา คำสั่งในนั้นจะถูกดำเนินการก่อนที่คุณจะได้รับพรอมต์ทุบตี (เครื่องหมาย $) ตัวอย่างเช่น PROMPT_COMMAND ของคุณคือ "echo 123" และคุณเรียกใช้ "ls" ในเทอร์มินัลของคุณ เอฟเฟกต์นั้นเหมือนกับการทำงาน "ls; echo 123"

$ PROMPT_COMMAND="echo 123"

เอาต์พุต (เช่นเดียวกับการเรียกใช้ 'PROMPT_COMMAND = "echo 123"; $ PROMPT_COMMAND'):

123

รันสิ่งต่อไปนี้:

$ echo 3

เอาท์พุท:

3
123

"history -a" ใช้เพื่อเขียนคำสั่ง history ในหน่วยความจำไปที่ ~ / .bash_history

"history -c" ใช้เพื่อล้างคำสั่งประวัติในหน่วยความจำ

"history -r" ใช้เพื่ออ่านคำสั่งประวัติจาก ~ / .bash_history ไปยังหน่วยความจำ

ดูคำอธิบายคำสั่งประวัติที่นี่: http://ss64.com/bash/history.html

PS: ตามที่ผู้ใช้คนอื่นได้ชี้ให้เห็นการส่งออกไม่จำเป็น ดู: การใช้การส่งออกใน. bashrc


2

ฉันได้เขียนสคริปต์สำหรับการตั้งค่าไฟล์ประวัติต่อเซสชั่นหรืองานของมันขึ้นอยู่กับดังต่อไปนี้

        # write existing history to the old file
        history -a

        # set new historyfile
        export HISTFILE="$1"
        export HISET=$1

        # touch the new file to make sure it exists
        touch $HISTFILE
        # load new history file
        history -r $HISTFILE

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

แหล่งที่มาเต็มรูปแบบ: https://github.com/simotek/scripts-config/blob/master/hiset.sh


2

นี่คือวิธีการแก้ปัญหาที่ไม่ได้รวมประวัติจากแต่ละช่วง

โดยทั่วไปจะมีการเก็บประวัติของแต่ละเซสชันแยกต่างหากและสร้างใหม่ในทุก ๆ การแจ้งเตือน ใช่มันใช้ทรัพยากรมากขึ้น แต่ก็ไม่ช้าอย่างที่ควรจะเป็น - ความล่าช้าเริ่มเห็นได้ชัดก็ต่อเมื่อคุณมีรายการประวัติมากกว่า 100,000 รายการ

นี่คือตรรกะหลัก:

# on every prompt, save new history to dedicated file and recreate full history
# by reading all files, always keeping history from current session on top.
update_history () {
  history -a ${HISTFILE}.$$
  history -c
  history -r
  for f in `ls ${HISTFILE}.[0-9]* | grep -v "${HISTFILE}.$$\$"`; do
    history -r $f
  done
  history -r "${HISTFILE}.$$"
}
export PROMPT_COMMAND='update_history'

# merge session history into main history file on bash exit
merge_session_history () {
  cat ${HISTFILE}.$$ >> $HISTFILE
  rm ${HISTFILE}.$$
}
trap merge_session_history EXIT

ดูส่วนสำคัญนี้สำหรับโซลูชันที่สมบูรณ์รวมถึงการป้องกันและการปรับแต่งประสิทธิภาพให้เหมาะสม


1

สิ่งนี้ใช้ได้กับ ZSH

##############################################################################
# History Configuration for ZSH
##############################################################################
HISTSIZE=10000               #How many lines of history to keep in memory
HISTFILE=~/.zsh_history     #Where to save history to disk
SAVEHIST=10000               #Number of history entries to save to disk
#HISTDUP=erase               #Erase duplicates in the history file
setopt    appendhistory     #Append history to the history file (no overwriting)
setopt    sharehistory      #Share history across terminals
setopt    incappendhistory  #Immediately append to the history file, not just when a term is killed

น่าเสียดายที่คำถามนี้มีไว้สำหรับการทุบตีอย่างเคร่งครัด :-)
Jaleks

1
มันเป็นผลครั้งแรกบน google เมื่อฉันค้นหา zsh เช่นกัน ... คิดว่ามันอาจช่วยได้
Mulki

3
คุณควรถามคำถามใหม่ ~ "เก็บประวัติ zsh ในหน้าต่างเทอร์มินัลหลายบาน" โดยสมมติว่าไม่มีอยู่จริง ไม่เป็นไรอย่างสมบูรณ์ - ผู้ได้รับการสนับสนุนเจ็ดคน - ตอบคำถามของคุณเองหากเป็นคำถามที่ดี
Oli

1

ฉันต้องการสิ่งนี้มานานโดยเฉพาะความสามารถในการเรียกคำสั่งโดยที่มันถูกเรียกใช้เพื่อรันใหม่ในโครงการใหม่ (หรือค้นหาไดเรกทอรีด้วยคำสั่ง) ดังนั้นฉันจึงรวมเครื่องมือนี้เข้าด้วยกันซึ่งรวมโซลูชันก่อนหน้าสำหรับการจัดเก็บประวัติ CLI ทั่วโลกเข้ากับเครื่องมือ grepping แบบโต้ตอบที่เรียกว่า percol (แมปกับ C ^ R) มันยังคงลื่นไหลในเครื่องแรกที่ฉันเริ่มใช้ตอนนี้ด้วยประวัติ CLI> 2 ปี

มันไม่ได้ยุ่งกับประวัติ CLI ท้องถิ่นเท่าที่ปุ่มลูกศรเกี่ยวข้อง แต่ช่วยให้คุณเข้าถึงประวัติศาสตร์โลกได้อย่างง่ายดาย (ซึ่งคุณสามารถแมปกับสิ่งอื่นที่ไม่ใช่ C ^ R)


นี่สำหรับ zsh?
sjas

1
ใช่ฉันทำเพื่อ zsh ในตอนแรก มันทำงานเพื่อทุบตีและตกปลาด้วยเหมือนกัน แจ้งให้เราทราบว่ามันใช้งานได้หรือไม่ ฉันไม่ได้เปลี่ยนไปซักพักแล้วและฉันก็ไม่แน่ใจว่าคำแนะนำในการติดตั้งของฉันชัดเจนแค่ไหน
Gordon Wells

1

เพราะฉันชอบประวัติอนันต์ที่บันทึกไว้ในไฟล์ที่กำหนดเอง ฉันสร้างการกำหนดค่านี้ตามhttps://stackoverflow.com/a/19533853/4632019 :

export HISTFILESIZE=
export HISTSIZE=
export HISTTIMEFORMAT="[%F %T] "

export HISTFILE=~/.bash_myhistory
PROMPT_COMMAND="history -a; history -r; $PROMPT_COMMAND"

-1

นี่คือตัวอย่างข้อมูลจาก. bashrc และคำอธิบายสั้น ๆ ทุกที่ที่ต้องการ:

# The following line ensures that history logs screen commands as well
shopt -s histappend

# This line makes the history file to be rewritten and reread at each bash prompt
PROMPT_COMMAND="$PROMPT_COMMAND;history -a; history -n"
# Have lots of history
HISTSIZE=100000         # remember the last 100000 commands
HISTFILESIZE=100000     # start truncating commands after 100000 lines
HISTCONTROL=ignoreboth  # ignoreboth is shorthand for ignorespace and     ignoredups

HISTFILESIZE และ HISTSIZE เป็นความชอบส่วนตัวและคุณสามารถเปลี่ยนได้ตามรสนิยมของคุณ

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