मैं अपने .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आदेश वास्तव में दो बार दर्ज किया जाएगा। मैंने समय-समय पर w / cron चलाने के बारे में सोचा है:

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

यह डुप्लिकेट को निकालना होगा, लेकिन दुर्भाग्य से आदेश संरक्षित नहीं होगा। अगर मुझे sortपहले फाइल नहीं आती है तो मुझे विश्वास नहीं होता कि मैं uniqठीक से काम कर सकता हूँ।

मैं अपने .bash_history में डुप्लिकेट को कैसे हटा सकता हूं, आदेश को संरक्षित कर सकता हूं?

अतिरिक्त श्रेय:

क्या .bash_historyस्क्रिप्ट के माध्यम से फ़ाइल को ओवरराइट करने में कोई समस्या है ? उदाहरण के लिए, यदि आप एक अपाचे लॉग फ़ाइल को हटाते हैं, तो मुझे लगता है कि आपको नोह / रीसेट सिग्नल भेजने की आवश्यकता killहै, क्योंकि यह फाइल से जुड़ा हुआ है। यदि .bash_historyफ़ाइल के मामले में ऐसा है , तो शायद मैं किसी भी तरह psसे जांचने के लिए उपयोग कर सकता हूं और सुनिश्चित कर सकता हूं कि फ़िल्टरिंग स्क्रिप्ट चलाने से पहले कोई जुड़े सत्र नहीं हैं?


3
थोड़ी देर के ignoredupsबजाय कोशिश करें erasedupsऔर देखें कि यह आपके लिए कैसे काम करता है।
jw013

1
मैं bash इतिहास फाइल करने के लिए एक खुली फ़ाइल संभाल रखती है नहीं लगता है - इसे पढ़ता है / यह लिखते हैं जब यह करने की जरूरत है, तो यह होना चाहिए (नोट - चाहिए - मैं परीक्षण नहीं किया) कहीं और से इसे अधिलेखित करना सुरक्षित हो।
19

1
मैंने अभी आपके प्रश्न के 1 वाक्य पर कुछ नया सीखा है। अच्छी चाल!
रिकार्डो

मैं historyकमांड के सभी विकल्पों के लिए मैन पेज खोजने में विफल रहा हूँ । मुझे कहाँ देखना चाहिए?
जोनाथन हार्टले

इतिहास विकल्प 'मैन बैश' में हैं, 'शेल बिलियन कमांड' सेक्शन के लिए खोज करें, फिर उसके नीचे 'इतिहास' के लिए।
जोनाथन हार्टले

जवाबों:


36

इतिहास को क्रमबद्ध करना

यह कमांड की तरह काम करता है sort|uniq, लेकिन लाइनों को जगह देता है

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

मूल रूप से, प्रत्येक पंक्ति को उसकी संख्या के लिए प्रस्तुत करता है। बाद में sort|uniq, सभी लाइनों को उनके मूल क्रम (लाइन नंबर फ़ील्ड का उपयोग करके) के अनुसार वापस सॉर्ट किया जाता है और लाइन नंबर फ़ील्ड को लाइनों से हटा दिया जाता है।

इस समाधान का दोष है कि यह अपरिभाषित है जो समान लाइनों के एक वर्ग के प्रतिनिधि इसे आउटपुट में बना देगा और इसलिए अंतिम आउटपुट में इसकी स्थिति अपरिभाषित है। हालाँकि, यदि नवीनतम प्रतिनिधि चुना जाना चाहिए तो आप sortदूसरी कुंजी द्वारा इनपुट कर सकते हैं :

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

प्रबंध .bash_history

फिर से पढ़ने और इतिहास लिखने के लिए, आप उपयोग कर सकते हैं history -aऔर history -wक्रमशः।


6
शेल टूल्स के साथ कार्यान्वित सजावट-सॉर्ट-अनडकोरेट का एक संस्करण । अच्छा लगा।
ire_and_curses

साथ sort, -rस्विच हमेशा छँटाई क्रम को उलट देता है। लेकिन यह आपके मन में आने वाले परिणाम नहीं देगा। परिणाम के समान sortदो घटनाओं के संबंध में ls, जो उलट होने पर भी, अंतिम क्रम छँटाई एल्गोरिथ्म पर निर्भर करता है। लेकिन एक और विचार के लिए मेरा अपडेट देखें।
कलाकार

1
मामले में, आप .bash_history को संशोधित नहीं करना चाहते, आप निम्नलिखित .bashrc में रख सकते हैं: उपनाम इतिहास = 'इतिहास | sort -k2 -k 1,1nr | uniq -f १ | सॉर्ट-एन '
नाथन

nlप्रत्येक कोड लाइन की शुरुआत में क्या है ? यह नहीं होना चाहिए history?
AL

1
@AL nl लाइन नंबर जोड़ता है। एक पूरे के रूप में कमांड सामान्य समस्या को हल करता है: आदेश को संरक्षित करते हुए डुप्लिकेट को हटाता है। स्टड से इनपुट पढ़ा जाता है।
आर्टिऑक्स

48

इसलिए मैं डुप्लिकेट से परेशान होने के बाद उसी सटीक चीज़ की तलाश में था, और पाया कि अगर मैं अपने ~ / .bash_profile (Mac) को संपादित करता हूं:

export HISTCONTROL=ignoreboth:erasedups

यह वही करता है जो आप चाहते थे, यह केवल किसी भी आदेश का नवीनतम रखता है। ignorebothवास्तव में सिर्फ करने जैसा है ignorespace:ignoredupsऔर वह erasedupsकाम पूरा करता है।

कम से कम मेरे मैक टर्मिनल पर यह काम एकदम सही है। यह यहाँ askubuntu.com पर मिला ।


10
इसका सही उत्तर होना चाहिए
MitchBroadhead

मैक्स ओएस एक्स योसेमाइट पर और उबंटू 14_04 पर परीक्षण किया गया
रिकार्डो

1
@ मिचब्रोडहेड से सहमत हैं। यह बाहरी क्रॉन-जॉब के बिना, बैश में ही समस्या का समाधान करता है। ubuntu 17.04 और 16.04 LTS
जॉर्ज जुंग

OpenBSD पर भी काम करता है। यह केवल किसी भी कमांड को हटाता है जिसे वह इतिहास फ़ाइल में जोड़ रहा है, जो मेरे लिए ठीक है। इतिहास फ़ाइल को छोटा करने का दिलचस्प प्रभाव है क्योंकि मैं ऐसी कमांड दर्ज करता हूं जो पहले डुप्लिकेट के रूप में मौजूद थीं। अब मैं अपनी इतिहास फ़ाइल को अधिकतम छोटा बना सकता हूं।
वीकेपॉइंट

1
यह केवल डुप्लिकेट, लगातार आदेशों की अनदेखी करता है। यदि आप दो दिए गए आदेशों के बीच बार-बार वैकल्पिक करते हैं, तो आपका बैश इतिहास डुप्लिकेट के साथ भर जाएगा
Dylanthepiguy

16

जंगली और परीक्षण में इस समाधान मिला:

awk '!x[$0]++'

पहली बार किसी पंक्ति ($ 0) का विशिष्ट मूल्य देखा जाता है, x [$ 0] का मूल्य शून्य है।
शून्य का मान इसके साथ उलटा है !और एक हो जाता है।
एक कथन जो किसी का मूल्यांकन करता है वह डिफ़ॉल्ट कार्रवाई का कारण बनता है, जो प्रिंट है।

इसलिए, पहली बार किसी विशिष्ट $0को देखा जाता है, इसे मुद्रित किया जाता है।

हर अगली बार (दोहराता है) का मान x[$0]बढ़ा दिया गया है,
इसका नकारात्मक मूल्य शून्य है, और शून्य का मूल्यांकन करने वाला एक बयान प्रिंट नहीं करता है।

अंतिम दोहराया मूल्य रखने के लिए, इतिहास को उल्टा करें और उसी awk का उपयोग करें:

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

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

वाह! वह बस काम कर गया। लेकिन यह सभी को हटाता है लेकिन पहली घटना मुझे लगता है। मैं इसे चलाने से पहले उदात्त पाठ का उपयोग करते हुए लाइनों के क्रम को उलट दूंगा। अब मैं इसे फिर से उलट दूंगा कि एक स्वच्छ इतिहास पाने के लिए सभी डुप्लिकेट की अंतिम घटना को पीछे छोड़ दिया जाए। धन्यवाद।
ट्रैस

मेरे जवाब की जाँच करें!
अली शकीबा

एक साफ-सुथरा और सामान्य उत्तर (इतिहास के उपयोग-मामले तक सीमित नहीं), एक उप-प्रक्रिया शुरू करने के बिना; ;-)
जेपीजेड

9

क्लेटन के उत्तर का विस्तार:

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

tacफ़ाइल को उल्टा करें, सुनिश्चित करें कि आपने स्थापित किया है, moreutilsइसलिए आपके पास spongeउपलब्ध है, अन्यथा एक अस्थायी फ़ाइल का उपयोग करें।


1
मैक पर उन लोगों के लिए, उपयोग करें brew install coreutilsऔर ध्यान दें कि सभी GNU gबर्तनों में BSD में निर्मित मैक कमांड (जैसे g GNU है जबकि सेड BSD है) के साथ भ्रम से बचने के लिए एक पूर्वनिर्धारित है। इसलिए उपयोग करें gtac
त्रालस्टोन

मुझे इतिहास -c और इतिहास -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

स्पष्ट रूप से, क्या मैं सही समझ रहा हूं कि आपने यहां दो (शानदार) समाधान दिखाए हैं, और एक उपयोगकर्ता को उनमें से किसी एक को निष्पादित करने की आवश्यकता है? या तो माणिक एक, या बैश एक?
जोनाथन हार्टले

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
  • इतिहास फ़ाइल के अंत में हिस्टैपेंड विकल्प बफर के इतिहास को जोड़ता है ($ HISTFILE)
  • इग्नेबॉथ और इरेडअप्स डुप्लिकेट प्रविष्टियों को $ HISTFILE में सहेजे जाने से रोकते हैं
  • प्रॉम्प्ट कमांड हिस्ट्री कैश को अपडेट करता है
    • history -n $ HISTFILE की सभी पंक्तियों को पढ़ता है जो कि अंतिम कैरिज वापसी के बाद से एक अलग टर्मिनल में हो सकती है
    • history -w $ HISTFILE को अद्यतन बफर लिखते हैं
    • history -c बफर को मिटा देता है इसलिए कोई दोहराव नहीं होता है
    • history -r $ HISTFILE को फिर से पढ़ता है, जो अब खाली बफ़र से जुड़ रहा है
  • awk script में प्रत्येक लाइन की पहली घटना होती है, जिसका वह सामना करता है। tacइसे उलट देता है, और फिर इसे वापस उलट देता है ताकि इतिहास में हाल के सबसे हालिया आदेशों के साथ इसे बचाया जा सके
  • rm / tmp फ़ाइल

हर बार जब आप एक नया शेल खोलते हैं, तो इतिहास में सभी डंप मिटा दिए जाते हैं, और हर बार जब आप Enterएक अलग शेल / टर्मिनल विंडो में कुंजी मारते हैं, तो यह फाइल से इस इतिहास को अपडेट करता है।



यदि "इग्नेबॉथ और इरेडअप्स डूप्स को सहेजने से रोकते हैं", तो आपको फ़ाइल से ड्यूप्स निकालने के लिए "awk" कमांड करने की आवश्यकता क्यों है? क्या यह इसलिए है क्योंकि "इग्नेबॉथ और इरेडअप्स" केवल लगातार होने वाले डंपों को बचाने से रोकते हैं ? पांडित्य होने के लिए क्षमा करें, मैं बस समझने की कोशिश कर रहा हूं।
जोनाथन हार्टले

1
eradesups केवल लगातार डुप्लिकेट मिटाता है। और आप सही हैं कि awk कमांड erupupes कमांड को डुप्लिकेट बनाता है जिससे यह सुपरफ्लस होता है।
मुस्कुराते हुए

धन्यवाद, इससे मुझे स्पष्ट हो जाता है कि क्या चल रहा है।
जोनाथन हार्टले

0

हर नए आदेश को रिकॉर्ड करने के लिए मुश्किल है। सबसे पहले आपको ~/.profileया इसके समान जोड़ने की आवश्यकता है :

HISTCONTROL=erasedups
PROMPT_COMMAND='history -w'

फिर आपको इसमें जोड़ना होगा ~/.bash_logout:

history -a
history -w

क्या आप मुझे यह समझने में मदद कर सकते हैं कि लॉगआउट करने पर, आपको इतिहास फ़ाइल को फिर से लिखने से पहले इतिहास को अलिखित इतिहास में संलग्न करने की आवश्यकता है? क्या आप 'परिशिष्ट' के बिना पूरी फाइल नहीं लिख सकते?
जोनाथन हार्टले
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.