.Bash_history'deki sıralarımı koruyarak kopyalarımı nasıl kaldırabilirim?


60

control+rKomuta geçmişimi yinelemeli olarak aramaktan zevk alıyorum. Kullanmak istediğim birkaç iyi seçenek buldum:

# 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

Benim için tek sorun, erasedupssadece sıralı kopyaları silmektir - bu komut dizileriyle:

ls
cd ~
ls

lsKomut aslında iki kez kaydedilecektir. Periyodik olarak w / cron çalışması hakkında düşündüm:

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

Bu, kopyaları çıkarmayı başarır, ancak maalesef sipariş korunmazdı. Ben yapmazsam sortdosyayı ilk inanmıyorum uniqdüzgün çalışabilir.

.Bash_history'deki sıralarımı koruyarak kopyalarımı nasıl kaldırabilirim?

Ekstra kredi:

.bash_historyDosyanın üzerine bir komut dosyası ile yazmak ile ilgili herhangi bir sorun var mı? Örneğin, bir apache günlük dosyasını kaldırırsanız, dosya ile killolan bağlantısını kesmek için bir nohup / reset sinyali göndermeniz gerektiğini düşünüyorum . Eğer .bash_historydosyada durum buysa , belki de bir şekilde psfiltreleme komut dosyası çalıştırılmadan önce bağlı oturum olmadığından emin olmak için kontrol edebilir ve kullanabilirim ?


3
Bir süre ignoredupsyerine deneyin ve bunun erasedupssizin için nasıl çalıştığını görün.
jw013

1
Bash'nin geçmiş dosyaya açık bir dosya tanıtıcısı tuttuğunu düşünmüyorum - gerektiğinde okur / yazar, bu yüzden başka bir yerden üzerine yazmak için güvenli olmalıdır (not - gerekir - test etmedim).
D_Bye

1
Sorunun ilk cümlesinde yeni bir şey öğrendim. İyi numara!
Ricardo,

historyKomuta tüm seçenekler için man sayfasını bulamıyorum . Nereye bakmalıyım?
Jonathan Hartley

Tarihçe seçenekleri 'man bash' şeklindedir, 'kabuk yerleşik komutları' bölümünü ve ardından 'geçmiş'i arayın.
Jonathan Hartley

Yanıtlar:


36

Geçmişi sıralama

Bu komut gibi çalışır sort|uniq, ancak çizgileri yerinde tutar.

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

Temel olarak, her satıra numarasını hazırlar. sort|uniqKurulduktan sonra , tüm satırlar orijinal sıralarına göre (satır numarası alanını kullanarak) geri sıralanır ve satır numarası alanı satırlardan kaldırılır.

Bu çözüm, hangi eşit hat sınıfının temsilcisinin çıktıda başarılı olacağı ve bu nedenle de nihai çıktıdaki konumu tanımsız olduğuna dair bir kusur vardır. Ancak, en son temsilci seçilmesi gerekirse, sortikinci bir tuşla girişi yapabilirsiniz :

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

.Bash_history Yönetme

Tarihi tekrar okumak ve yazmak için sırasıyla history -ave history -wdüğmelerini kullanabilirsiniz .


6
Kabuk araçlarıyla uygulanan decorate-sort-undecorate'in bir sürümü . Güzel.
ire_and_curses

İle sort, -ranahtar hep sıralama tersten yapılır. Fakat bu aklınızdaki sonucu vermeyecektir. sonuçla özdeş olan sortiki durumu ls, tersine çevrildiğinde bile, sıralamanın sıralama algoritmasına bağlı olduğunu düşünür. Ancak başka bir fikir için güncellememe bakın.
artistoex

1
.Bash_history'de değişiklik yapmak istemezseniz, aşağıdakileri .bashrc içine koyabilirsiniz: alias history = 'history | sıralama -k2 -k 1,1nr | uniq -f 1 | sort -n '
Nathan

nlHer kod satırının başında ne var ? Olmamalı mı history?
AL,

1
@AL nl, satır numaralarını ekler. Bir bütün olarak komut genel sorunu çözer: sırayı korurken kopyaları çıkarmak. Giriş stdin'den okunur.
artistoex

48

Bu yüzden aynı şeyi çiftler tarafından kızdırdıktan sonra da aynı şeyi arıyordum ve ~ / .bash_profile (Mac) 'i düzenleyerek eğer:

export HISTCONTROL=ignoreboth:erasedups

Tam olarak istediğini yapar, sadece herhangi bir komutun sonunu tutar. ignorebothAslında sadece yapmak gibi ignorespace:ignoredupsve bununla birlikte erasedupsiş yapılır.

En azından benim Mac terminalimde bash ile bu iş mükemmel. Askubuntu.com sitesinde burada bulundu .


10
bu doğru cevap olmalıdır
MitchBroadhead

Max OS X Yosemite ve Ubuntu 14_04 ile test edildi
Ricardo

1
@ MitchellBroadhead ile katılıyorum. Bu, dış cron-işi olmadan, bash içindeki sorunu çözer. ubuntu 17.04 ve 16.04 LTS üzerinde test etti
Georg Jung

OpenBSD üzerinde de çalışır. Yalnızca benim için uygun olan geçmiş dosyasına eklediği herhangi bir komutun kopyalarını kaldırır. Daha önce kopyalanmış olan komutları girdiğimde tarih dosyasını kısaltmanın ilginç etkisi var. Artık tarih dosyamı daha az kısaltabilirim.
WeakPointer

1
Bu sadece arka arkaya yinelenen komutları yok sayar. Verilen iki komut arasında art arda geçiş yaparsanız, bash geçmişiniz yinelenenlerle doldurur
Dylanthepiguy

16

Bu çözümü vahşi ortamda buldum ve test ettik:

awk '!x[$0]++'

Bir çizginin belirli bir değeri ($ 0) ilk kez göründüğünde, x [$ 0] değeri sıfırdır.
Sıfır değeri ile ters çevrilir !ve bir olur.
Birine göre değerlendirilen bir ifade, yazdırılan varsayılan eyleme neden olur.

Bu nedenle, belirli bir ilk $0görüldüğünde, yazdırılır.

Bir dahaki sefere (tekrarlar) değeri x[$0]artırıldı,
olumsuz değeri sıfırdır ve sıfırı değerlendiren bir ifade yazdırılmaz.

Son tekrarlanan değeri korumak için geçmişi tersine çevirin ve aynı awk değerini kullanın:

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

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

Vaov! Bu sadece çalıştı. Ama sanırım ilk olay dışında hepsini kaldırıyor. Bunu çalıştırmadan önce Sublime Text kullanarak satırların sırasını değiştirdim. Şimdi, geriye kalan tüm kopyaların yalnızca son kez ortaya çıktığı temiz bir geçmiş elde etmek için tekrar tersine çevireceğim. Teşekkür ederim.
trss

Cevabımı kontrol et!
Ali Shakiba

Bazilyon alt süreçleri başlatmadan temiz ve genel cevap (tarihin kullanım durumuyla sınırlı değil) ;-)
JepZ

9

Clayton cevabını genişletme:

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

tacEğer yüklü olduğundan emin olun, dosyayı ters moreutilssahip böylece spongeaksi bir geçici dosya kullanmak, mevcut.


1
Mac'tekiler için, kullanın brew install coreutilsve tüm GNU yardımcı programlarının gBSD yerleşik Mac komutlarıyla karıştırılmaması için bir hazırlığa sahip olduklarına dikkat edin (örn. Gsed, GNU iken sed BSD'dir). Öyleyse kullan gtac.
tralston

Tarihi kullanabilmek için tarihçeye
-c'ye

4

Bunlar kopyalanan son satırları koruyacaktır:

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

Açık olmak gerekirse, burada iki (görkemli) çözüm gösterdiğinizi ve bir kullanıcının yalnızca birini çalıştırması gerektiğini doğru mu anladım? Ya yakut olan, ya da Bash olan?
Jonathan Hartley

3

Bu eski bir gönderidir, ancak birden fazla terminal açmak ve geçmişini pencereler arasında senkronize etmek, ancak kopyalanmamak isteyen kullanıcılar için kalıcı bir sorun.

.Bashrc'deki çözümüm:

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 seçeneği, arabellek geçmişini geçmiş dosyasının sonuna ekler ($ HISTFILE)
  • görmezden gelinen ve silinen kayıtlar yinelenen girişlerin $ HISTFILE dizinine kaydedilmesini önler
  • Prompt komutu geçmiş önbelleğini günceller
    • history -n Son satırın dönüşünden bu yana farklı bir terminalde oluşmuş olan $ HISTFILE satırlarını okur
    • history -w güncellenmiş arabelleği $ HISTFILE’e yazar
    • history -c Tamponu siler böylece çoğaltma gerçekleşmez
    • history -r şimdi boş arabellek ekleyerek $ HISTFILE yeniden okur
  • awk betiği, karşılaştığı her satırın ilk oluşumunu saklar. tactersine çevirir ve daha sonra geri döndürür, böylece tarihin en yenisi olan en son komutlarla kaydedilebilir
  • rm / tmp dosyası

Her yeni bir kabuk açtığınızda, geçmişin tüm kopyaları silinir ve Enteranahtara farklı bir kabuk / terminal penceresinde her basışınızda, bu geçmişi dosyadan günceller.



Eğer "görmezden gelinen ve silinenler, dupeslerin kaydedilmesini engeller" ise, o zaman neden dupesleri dosyadan kaldırmak için "awk" komutunu da yapmanız gerekir. Bu "görmezden gelinen ve silinen" lerin sadece art arda gelen çiftleri kurtarmasını engellediği için mi? Pedantik olduğum için üzgünüm, sadece anlamaya çalışıyorum.
Jonathan Hartley

1
Silinenler sadece ardışık kopyaları siler. Ve awk komutunun, silmeyi zorunlu kılan erasedupes komutunu çoğaltması doğru.
smilingfrog

Teşekkürler, bu bana neler olduğunu açıkça gösteriyor.
Jonathan Hartley

0

Her yeni komutu uniqely olarak kaydetmek zordur. Öncelikle ~/.profileveya benzeri eklemeniz gerekir :

HISTCONTROL=erasedups
PROMPT_COMMAND='history -w'

O zaman eklemeniz gerekir ~/.bash_logout:

history -a
history -w

Neden, oturumu kapattığınızda, tüm geçmiş dosyasını yeniden yazmadan önce geçmiş dosyasına yazılı bir tarih eklemeniz gerektiğini anlamamıza yardımcı olabilir misiniz? 'Ekleme' olmadan tüm dosyayı yazamaz mısın?
Jonathan Hartley
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.