bash_history: แสดงความคิดเห็นคำสั่งที่เป็นอันตราย: `#`


16

เพื่อป้องกันการบันทึกคำสั่ง "อันตราย" ในประวัติทุบตีฉันได้เพิ่มบรรทัดต่อไปนี้ใน.bashrcไฟล์ของฉัน:

HISTIGNORE='rm *:mv *:cp *:cat*>*:pv*>*'

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

history | grep Sep-28

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

ฉันไม่รู้ว่ามันเป็นไปได้ไหม

ปรับปรุงและชี้แจง:

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

PROMPT_COMMAND="history -a; history -c; history -r"

ลองจินตนาการว่าฉันเปิดเทอร์มินัลสองเครื่อง ในหนึ่งฉันมีcat /dev/foo > file.outกระบวนการทำงานบางอย่าง ls -lAhFในครั้งที่สองฉันจะตรวจสอบความคืบหน้าด้วย ฉันทำซ้ำlsโดยการกดUpและENTER(นั่นคือคำสั่งสุดท้ายจากประวัติ) ทันทีที่เสร็จสิ้นคำสั่งแรกที่คำสั่งสุดท้ายจากประวัติศาสตร์จะไม่มีอีกต่อไปแต่ls cat /dev/foo > file.outถ้าฉันไม่ระวังฉันจะเริ่ม cat อีกครั้งและเขียนทับ file.out

สิ่งที่ฉันต้องการบรรลุคือคำสั่ง cat จะถูกนำหน้าด้วย a #เพื่อที่จะไม่ถูกเรียกใช้งาน อย่างไรก็ตามฉันยังคงเห็นมันในประวัติศาสตร์และสามารถนำมาใช้ซ้ำได้ (หากเป็นคำสั่งที่ยาว) โดยยกเลิกการแสดงความคิดเห็น


แทนที่จะทำซ้ำคำสั่งด้วยตนเองคุณสามารถใช้watch ls -lAhFหรือwhile sleep 1; do ls -lAhf; done; แทนที่จะดูขนาดไฟล์คุณสามารถใช้pv /dev/foo > file.out( ivarch.com/programs/pv.shtml )
deltab

คำตอบ:


9

คุณสามารถทำสิ่งที่ชอบ:

fixhist() {
   local cmd histnum
   cmd=$(HISTTIMEFORMAT=/ history 1)
   histnum=$((${cmd%%[*/]*}))
   cmd=${cmd#*/} # remove the histnum
   case $cmd in
     (rm\ *|mv\ *|...)
       history -d "$histnum" # delete
       history -s "#$cmd"    # add back with a #
   esac
}
PROMPT_COMMAND=fixhist

ความคิดที่ว่าก่อนที่จะให้แต่ละเราจะตรวจสอบรายการประวัติศาสตร์ที่ผ่านมา ( history 1) และถ้าหนึ่งในมันอันตรายคนที่เราลบมัน ( history -d) และเพิ่มกลับมาพร้อมกับกับ#history -s

(แน่นอนคุณต้องลบHISTIGNOREการตั้งค่าของคุณ)

ผลข้างเคียงที่ไม่พึงประสงค์ของว่าที่คือว่ามันจะเปลี่ยนแปลงเวลาประวัติศาสตร์ของคนเหล่านั้นrm, mv... คำสั่ง

ในการแก้ไขปัญหานั้นทางเลือกอาจเป็น:

fixhist() {
   local cmd time histnum
   cmd=$(HISTTIMEFORMAT='<%s>' history 1)
   histnum=$((${cmd%%[<*]*}))
   time=${cmd%%>*}
   time=${time#*<}
   cmd=${cmd#*>}
   case $cmd in
     (rm\ *|mv\ *|...)
       history -d "$histnum" # delete
       HISTFILE=/dev/stdin history -r <<EOF
#$time
#$cmd
EOF
   esac
}
PROMPT_COMMAND=fixhist

เวลานี้เราบันทึกเวลาของประวัติครั้งล่าสุดและเพื่อเพิ่มกลับบรรทัดประวัติศาสตร์เราใช้history -rจากไฟล์ชั่วคราว (เอกสารที่นี่) ซึ่งรวมถึงการประทับเวลา

คุณจะต้องการที่จะดำเนินการก่อนวันที่fixhist history -a; history -c; history -rน่าเสียดายที่เวอร์ชันปัจจุบันของbashมีข้อบกพร่องที่history -aไม่ได้บันทึกบรรทัดพิเศษที่เราได้เพิ่มไว้ การหลีกเลี่ยงคือเขียนแทน:

fixhist() {
   local cmd time histnum
   cmd=$(HISTTIMEFORMAT='<%s>' history 1)
   histnum=$((${cmd%%[<*]*}))
   time=${cmd%%>*}
   time=${time#*<}
   cmd=${cmd#*>}
   case $cmd in
     (rm\ *|mv\ *|...)
       history -d "$histnum" # delete
       history -a
       [ -f "$HISTFILE" ] && printf '#%s\n' "$time" "$cmd" >> "$HISTFILE";;
     (*)
       history -a
   esac
   history -c
   history -r
}
PROMPT_COMMAND=fixhist

นั่นคือการผนวกคำสั่งที่ใส่เครื่องหมายคอมเมนต์ไว้กับ HISTFILE แทนการปล่อยให้history -aทำ


คุณช่วยอธิบายได้cmd=${cmd#*[0-9] }ไหม และที่ว่าผมควรใส่fixhistในของฉันPROMPT_COMMAND? ในตอนนี้มันมีอยู่แล้วPROMPT_COMMAND="history -a; history -c; history -r"
Martin Vegter

บทบาทของHISTTIMEFORMAT=/อะไร export HISTTIMEFORMAT="%b-%d %H:%M "ฉันได้กำหนดไว้แล้ว อย่างไรก็ตามเมื่อฉันเพิ่มรหัสของคุณในของฉัน$HOME/.bashrcไม่มีอะไรเกิดขึ้น
Martin Vegter

HISTTIMEFORMAT=/มีไว้สำหรับการเรียกใช้เพียงครั้งเดียวhistoryเพื่อให้ได้เอาต์พุตเช่น123 /rm xที่ง่ายกว่าในการแตกไฟล์ cmd มีปัญหากับบางรุ่นของbashที่$HISTCMDปลอมในบริบทนั้นลองรุ่นใหม่
Stéphane Chazelas

ยังคงไม่ทำงาน ฉันสงสัยว่า#ในรหัสไม่ทำหน้าที่เป็นความคิดเห็นใน.bashrc?
Martin Vegter

1
@MartinVegter ใช่สำหรับรายการประวัติที่ถูกแก้ไขให้bashแทรกหมายเลข*ตามหลังประวัติที่ไม่ได้คาดไว้ ควรได้รับการแก้ไขแล้ว
Stéphane Chazelas

11

ฉันจะไม่ตอบคำถามของคุณอย่างแน่ชัด แต่อาจให้ทางเลือกอื่นแก่คุณในการแก้ปัญหา

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

ในกรณีนี้ดีทุบตีhistverifyตัวเลือก หากคุณshopt -s histverifyและถ้าคุณจำคำสั่งด้วยเสียง!ระเบิดคำสั่งนั้นจะไม่ถูกเรียกใช้งานทันที แต่จะถูกโหลดใน readline เพื่อให้คุณสามารถตัดสินใจที่จะรันมันได้หรือไม่และสิ่งนี้ยังช่วยให้คุณสามารถแก้ไขได้

ลองมัน:

  • โดยไม่ต้องhistverify:

    $ touch some_foo
    $ rm some_foo
    $ touch some_foo
    $ !rm
    rm some_foo
    $ # oooops in fact I'd've like to keep it this time
  • ด้วยhistverify:

    $ shopt -s histverify
    $ touch some_foo
    $ rm some_foo
    $ touch some_foo
    $ !rm
    $ rm some_foo <cursor here>

    ในกรณีนี้คุณจะมีเคอร์เซอร์ที่ท้ายบรรทัดพร้อมที่จะเปิดอีกครั้ง - หรือไม่ - หรือเพื่อแก้ไข

ถ้าคุณชอบตัวเลือกนี้ให้ใส่ไว้ใน.bashrc:

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