मैं डायरेक्टरी ट्री की सबसे पुरानी फाइल कैसे पा सकता हूं


70

मैं एक निर्देशिका ट्री में सबसे पुरानी फ़ाइल खोजने के लिए शेल वन-लाइनर की तलाश कर रहा हूं।

जवाबों:


72

यह काम करता है (डैनियल एंडरसन के सुझाव को शामिल करने के लिए अद्यतन):

find -type f -printf '%T+ %p\n' | sort | head -n 1

8
कम टाइपिंग:find -type f -printf '%T+ %p\n' | sort | head -1
डैनियल एंडरसन

1
मुझे खाली जगह मिलती है क्योंकि मेरी पहली पंक्ति इस findतथ्य से खाली है क्योंकि मेरे पास फ़ाइल नाम नई लाइन है।
। 林果

1
क्या मैं यह पूछ सकता हूं कि क्या यह निर्मित या संशोधन तिथि का उपयोग करता है?
मृमेसेस

1
लिनक्स फ़ाइल निर्माण की तारीख को कहीं भी संग्रहीत नहीं करता है [*]। यह संशोधन तिथि का उपयोग करता है। [*] यह वास्तव में सच नहीं है; ext4 इनोड निर्माण तिथि को संग्रहीत करता है, लेकिन यह किसी भी सिस्टम कॉल के माध्यम से उजागर नहीं होता है और इसे देखने के लिए आपको
डिबगफ्यूज़

11

यह थोड़ा अधिक पोर्टेबल है और क्योंकि यह GNU findएक्सटेंशन पर निर्भर नहीं है -printf, इसलिए यह BSD / OS X पर भी काम करता है:

find . -type f -print0 | xargs -0 ls -ltr | head -n 1

यहाँ केवल नकारात्मक पक्ष यह है कि यह कुछ हद तक सीमित है ARG_MAX(जो कि सबसे नए गुठली के लिए अप्रासंगिक होना चाहिए )। इसलिए, यदि getconf ARG_MAXमेरे सिस्टम में 262,144 से अधिक वर्ण वापस आ गए हैं, तो यह आपको सही परिणाम नहीं देता है। यह भी POSIX- अनुरूप नहीं है क्योंकि -print0और xargs -0नहीं है।

इस समस्या के कुछ और समाधान यहाँ दिए गए हैं: मैं एक निर्देशिका में नवीनतम (सबसे नई, सबसे पुरानी, ​​सबसे पुरानी) फ़ाइल कैसे ढूँढ सकता हूँ? - ग्रेग का विकी


यह भी काम करता है, लेकिन यह भी xargs: ls: terminated by signal 13साइड इफेक्ट के रूप में एक त्रुटि का उत्सर्जन करता है। मैं अनुमान लगा रहा हूं कि यह SIGPIPE है। मुझे नहीं पता कि जब मैं अपने समाधान में सिर को आउटपुट करता हूं तो मुझे एक समान त्रुटि क्यों नहीं मिलती है।
मारियस गेदमिनस

आपका संस्करण मेमोरी से टाइप करना भी आसान है। :-)
मारियस गेदमिनस

हां, वह टूटा हुआ पाइप है। मुझे यह उन सभी कमांडों के GNU और BSD दोनों संस्करणों के साथ नहीं मिलता है, लेकिन यह headकमांड है जो एक बार लाइन को पढ़ने के बाद क्विट करता है और इस तरह पाइप को "ब्रेक" करता है, मुझे लगता है। आपको त्रुटि नहीं मिलती है क्योंकि sortइसके बारे में शिकायत नहीं लगती है, लेकिन lsदूसरे मामले में करता है।
slhck

4
यह टूट जाता है अगर वहाँ बहुत सारे फ़ाइलनाम हैं जिन्हें एक से अधिक बार xargsआह्वान करने की आवश्यकता है ls। उस स्थिति में, उन एकाधिक चालानों के क्रमबद्ध आउटपुट समाप्त हो जाते हैं जब उन्हें विलय किया जाना चाहिए।
निकोल हैमिल्टन

2
मुझे लगता है कि यह एक स्क्रिप्ट को पोस्ट करने से भी बदतर है जो मानता है कि फ़ाइल नाम में कभी भी रिक्त स्थान नहीं होते हैं। बहुत समय, वे काम करेंगे क्योंकि फ़ाइल नाम में स्थान नहीं हैं। और जब वे असफल होते हैं, तो आपको एक त्रुटि मिलती है। लेकिन यह वास्तविक मामलों में काम करने की संभावना नहीं है और विफलता अनदेखा हो जाएगी। किसी भी डाइरेक्टरी ट्री पर इतना बड़ा कि आप बस lsउसे नहीं देख सकते हैं और सबसे पुरानी फाइल को देख सकते हैं, आपका समाधान संभवतः कमांड लाइन की लंबाई सीमा को पार कर जाएगा , जिससे lsकई बार आह्वान किया जा सकता है। आपको गलत उत्तर मिल जाएगा, लेकिन आप कभी नहीं जान पाएंगे।
निकोल हैमिल्टन

11

निम्न आदेशों को किसी भी तरह के अजीब फ़ाइल नामों के साथ काम करने की गारंटी है:

find -type f -printf "%T+ %p\0" | sort -z | grep -zom 1 ".*" | cat

find -type f -printf "%T@ %T+ %p\0" | \
    sort -nz | grep -zom 1 ".*" | sed 's/[^ ]* //'

stat -c "%y %n" "$(find -type f -printf "%T@ %p\0" | \
    sort -nz | grep -zom 1 ".*" | sed 's/[^ ]* //')"

\0एक लाइनफीड कैरेक्टर ( ) के बजाय एक अशक्त बाइट ( ) का उपयोग करना \nसुनिश्चित करता है कि फाइल के नामों में से एक लाइनफीड कैरेक्टर के मामले में खोज का आउटपुट अभी भी समझ में आएगा।

-zस्विच दोनों तरह और ग्रेप अंत लाइन पात्रों के रूप में केवल अशक्त बाइट्स की व्याख्या करता है। चूंकि सिर के लिए ऐसा कोई स्विच नहीं है, हम grep -m 1इसके बजाय (केवल एक घटना) का उपयोग करते हैं।

आदेशों का निष्पादन समय (मेरी मशीन पर मापा गया) द्वारा किया जाता है।

  • पहला कमांड सबसे धीमा होगा क्योंकि इसमें हर फाइल के माइम को पहले मानव पठनीय प्रारूप में बदलना होगा और फिर उन स्ट्रिंग्स को क्रमबद्ध करना होगा। बिल्ली के लिए पाइपिंग उत्पादन को रंग देने से बचा जाता है।

  • दूसरा कमांड थोड़ा तेज है। हालांकि यह अभी भी दिनांक रूपांतरण करता है, संख्यात्मक रूप से छांटना ( sort -n) उन सेकंडों को समाप्त कर देता है जब से यूनिक्स युग थोड़ा तेज होता है। यूनिक्स के युग के बाद सेड सेकंड को हटा देता है।

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

संबंधित मैन पेज: खोज - grep - sed - सॉर्ट - स्टेट


5

यद्यपि स्वीकृत उत्तर और यहां अन्य लोग काम करते हैं, यदि आपके पास एक बहुत बड़ा पेड़ है, तो वे सभी फाइलों के पूरे गुच्छा को सॉर्ट करेंगे।

बेहतर यह होगा कि हम उन्हें सूचीबद्ध कर सकें और सबसे पुराने को ट्रैक कर सकें, बिना किसी क्रम के।

यही कारण है कि मैं इस वैकल्पिक समाधान के साथ आया:

ls -lRU $PWD/* | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { gsub(/-/,"",$6); if (substr($1,0,1)=="/") { pat=substr($1,0,length($0)-1)"/"; }; if( $6 != "") {if ( $6 < oldd ) { oldd=$6; oldf=pat$8; }; print $6, pat$8; count++;}} END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'

मुझे उम्मीद है कि यह किसी भी मदद का हो सकता है, भले ही सवाल थोड़ा पुराना हो।


संपादित 1: यह परिवर्तन रिक्त स्थान के साथ फ़ाइलों और निर्देशिकाओं को पार्स करने की अनुमति देता है। यह तेजी से जड़ में जारी करने /और अब तक की सबसे पुरानी फ़ाइल खोजने के लिए पर्याप्त है ।

ls -lRU --time-style=long-iso "$PWD"/* | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { gsub(/-/,"",$6); if (substr($0,0,1)=="/") { pat=substr($0,0,length($0)-1)"/"; $6="" }; if( $6 ~ /^[0-9]+$/) {if ( $6 < oldd ) { oldd=$6; oldf=$8; for(i=9; i<=NF; i++) oldf=oldf $i; oldf=pat oldf; }; count++;}} END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'

कमांड समझाया:

  • ls -lRU --time-style = long-iso "$ PWD" / * सभी फाइलों (*), लंबे प्रारूप (l), पुनरावर्ती (R) को सूचीबद्ध करता है, बिना छँटाई के (U), तेज़ होने के लिए, और इसे जागने के लिए पाइप करें
  • इसके बाद काउंटर (इस प्रश्न के लिए वैकल्पिक) को शून्य करके और आज की होने वाली सबसे पुरानी तारीख को सेट करें, वर्षमान को प्रारूपित करें।
  • पहले मुख्य लूप
    • 6 वें क्षेत्र, दिनांक, प्रारूप वर्ष-महीना-दिवस को पकड़ता है, और इसे बदलकर YearMonthDay (यदि आपका एलएस इस तरह से आउटपुट नहीं करता है, तो आपको इसे ठीक करने की आवश्यकता हो सकती है)।
    • पुनरावर्ती का उपयोग करना, सभी निर्देशिकाओं के लिए / निर्देशिका / यहाँ के रूप में हैडर लाइनें होंगी:। इस लाइन को पैट वेरिएबल में पकड़ें। (अंतिम ":" को "a /" में प्रतिस्थापित करता है)। और हेडर लाइन को मान्य फ़ाइल लाइन के रूप में उपयोग करने से बचने के लिए $ 6 को कुछ भी नहीं सेट करता है।
    • यदि फ़ील्ड $ 6 में एक वैध संख्या है, तो इसकी तारीख। पुरानी तारीख पुरानी के साथ तुलना करें।
    • क्या यह अधिक पुराना है? फिर पुराने दिनांक पुराने और पुराने फ़ाइल नाम oldf के लिए नए मान सहेजें। BTW, पुराना न केवल 8 वीं क्षेत्र है, बल्कि 8 वीं से अंत तक है। यही कारण है कि 8 वें से एनएफ (अंत) के लिए एक लूप को बदलना है।
    • एक एक करके गिनती आगे बढ़ाएं
    • परिणाम प्रिंट करके अंत

इसे चलाना:

~ $ time ls -lRU "$ PWD" / * | जाग आदि।

सबसे पुरानी तारीख: 19691231

फाइल: /home/../../backupold/.../EXAMPLES/how-to-program.txt

कुल तुलना: 111438

वास्तविक 0m1.135s

उपयोगकर्ता 0m0.872s

sys 0m0.760s


संपादित करें 2: एक ही अवधारणा है, बेहतर समाधान का उपयोग findको देखने के लिए उपयोग समय (का उपयोग %Tपहले से printfके लिए संशोधन समय या %Cके लिए स्थिति परिवर्तन के बजाय)।

find . -wholename "*" -type f -printf "%AY%Am%Ad %h/%f\n" | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { if ($1 < oldd) { oldd=$1; oldf=$2; for(i=3; i<=NF; i++) oldf=oldf " " $i; }; count++; } END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'

EDIT 3: कमांड बलो संशोधन समय का उपयोग करता है और वृद्धिशील प्रगति को भी प्रिंट करता है क्योंकि यह पुरानी और पुरानी फाइलों को ढूंढता है, जो तब उपयोगी होता है जब आपके पास कुछ गलत टाइमस्टैम्प्स (जैसे 1970-01-01):

find . -wholename "*" -type f -printf "%TY%Tm%Td %h/%f\n" | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { if ($1 < oldd) { oldd=$1; oldf=$2; for(i=3; i<=NF; i++) oldf=oldf " " $i; print oldd " " oldf; }; count++; } END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'

यह अभी भी रिक्त स्थान के साथ फ़ाइलों को स्वीकार करने के लिए tweeking की आवश्यकता है। मैं जल्द ही ऐसा करूंगा।
डॉ। बीको

मुझे लगता है कि रिक्त स्थान के साथ फ़ाइलों के लिए पार्सिंग ls एक अच्छा विचार नहीं है। शायद खोजने का उपयोग कर।
डॉ। बीको

बस इसे पूरे पेड़ "/" में चलाएं। समय व्यतीत: कुल तुलना: 585744 असली 2m14.017s उपयोगकर्ता 0m8.181s 0m8.473s sys
डॉ।

उपयोग करना lsस्क्रिप्टिंग के लिए बुरा है क्योंकि इसका आउटपुट मशीनों के लिए नहीं है, आउटपुट स्वरूपण पूरे कार्यान्वयन में भिन्न होता है। जैसा कि आपने पहले ही बताया findहै कि यह स्क्रिप्टिंग के लिए अच्छा है, लेकिन lsसमाधान के बारे में बताने से पहले उस जानकारी को जोड़ना भी अच्छा हो सकता है ।
संपो सरला

4

कृपया ls का उपयोग करें - मैन पेज आपको बताता है कि डायरेक्टरी को कैसे ऑर्डर करना है।

ls -clt | head -n 2

-N 2 है, इसलिए आपको आउटपुट में "कुल" नहीं मिलता है। यदि आप केवल फ़ाइल का नाम चाहते हैं।

ls -t | head -n 1

और अगर आपको सामान्य क्रम में सूची की आवश्यकता है (नवीनतम फ़ाइल प्राप्त करना)

ls -tr | head -n 1

खोजने के लिए उपयोग करने की तुलना में बहुत आसान है, बहुत तेज है, और अधिक मजबूत है - फ़ाइल नामकरण स्वरूपों के बारे में चिंता करने की ज़रूरत नहीं है। यह लगभग सभी प्रणालियों पर भी काम करना चाहिए।


6
यह केवल तभी काम करता है जब फाइलें एकल निर्देशिका में होती हैं, जबकि मेरा सवाल एक निर्देशिका पेड़ के बारे में था।
मारीस गेदमिनस

2
find ! -type d -printf "%T@ %p\n" | sort -n | head -n1

यह ठीक से काम नहीं करेगा अगर 9 सितंबर 2001 से अधिक पुरानी फाइलें हैं (यूनिक्स युग के बाद से 1000000000 सेकंड)। संख्यात्मक छँटाई सक्षम करने के लिए, का उपयोग करें sort -n
डेनिस

यह मुझे फ़ाइल खोजने में मदद करता है, लेकिन यह देखना मुश्किल है कि यह दूसरी कमान चलाने के बिना कितना पुराना है :)
Marius Gedminas

0

ऐसा लगता है कि "सबसे पुराने" द्वारा अधिकांश लोगों ने माना है कि आपका मतलब "सबसे पुराना संशोधन समय" था। शायद "सबसे पुराना" की सबसे सख्त व्याख्या के अनुसार, इसे सही किया गया है, लेकिन यदि आप सबसे पुराने पहुंच समय के साथ चाहते हैं , तो मैं सबसे अच्छा उत्तर इस प्रकार संशोधित करूंगा:

find -type f -printf '%A+ %p\n' | sort | head -n 1

ध्यान दें %A+


-1
set $(find /search/dirname -type f -printf '%T+ %h/%f\n' | sort | head -n 1) && echo $2
  • find ./search/dirname -type f -printf '%T+ %h/%f\n' दो स्तंभों में दिनांक और फ़ाइल नाम प्रिंट करता है।
  • sort | head -n1 सबसे पुरानी फ़ाइल के अनुरूप लाइन रखता है।
  • echo $2 दूसरा कॉलम, यानी फ़ाइल नाम प्रदर्शित करता है।

1
सुपर उपयोगकर्ता में आपका स्वागत है! हालांकि यह प्रश्न का उत्तर दे सकता है, यह एक बेहतर उत्तर होगा यदि आप कुछ स्पष्टीकरण प्रदान कर सकते हैं कि ऐसा क्यों होता है।
DavidPostill

1
ध्यान दें, कई लोगों ने आपके पिछले (समान) हटाए गए उत्तर के कुछ स्पष्टीकरण भी मांगे थे।
DavidPostill

क्या जवाब देना मुश्किल है? find ./search/dirname -type f -printf '% T +% h /% f \ n' | सॉर्ट | हेड -n 1 यह फ़ाइल के समय और पथ के रूप में दो कॉलम दिखाता है। पहले कॉलम को निकालना आवश्यक है। सेट का उपयोग और प्रतिध्वनि $ 2
दीमा

1
आपको कई अन्य उपयोगकर्ताओं द्वारा अनुरोध के अनुसार, केवल एक कमांड लाइन चिपकाने के बजाय स्पष्टीकरण प्रदान करना चाहिए।
Ob1lan

1
यह कैसे अलग है फिर स्वीकृत उत्तर?
रामहाउंड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.