मैं एक निर्देशिका ट्री में सबसे पुरानी फ़ाइल खोजने के लिए शेल वन-लाइनर की तलाश कर रहा हूं।
मैं एक निर्देशिका ट्री में सबसे पुरानी फ़ाइल खोजने के लिए शेल वन-लाइनर की तलाश कर रहा हूं।
जवाबों:
यह काम करता है (डैनियल एंडरसन के सुझाव को शामिल करने के लिए अद्यतन):
find -type f -printf '%T+ %p\n' | sort | head -n 1
find
तथ्य से खाली है क्योंकि मेरे पास फ़ाइल नाम नई लाइन है।
यह थोड़ा अधिक पोर्टेबल है और क्योंकि यह 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 है। मुझे नहीं पता कि जब मैं अपने समाधान में सिर को आउटपुट करता हूं तो मुझे एक समान त्रुटि क्यों नहीं मिलती है।
head
कमांड है जो एक बार लाइन को पढ़ने के बाद क्विट करता है और इस तरह पाइप को "ब्रेक" करता है, मुझे लगता है। आपको त्रुटि नहीं मिलती है क्योंकि sort
इसके बारे में शिकायत नहीं लगती है, लेकिन ls
दूसरे मामले में करता है।
xargs
आह्वान करने की आवश्यकता है ls
। उस स्थिति में, उन एकाधिक चालानों के क्रमबद्ध आउटपुट समाप्त हो जाते हैं जब उन्हें विलय किया जाना चाहिए।
ls
उसे नहीं देख सकते हैं और सबसे पुरानी फाइल को देख सकते हैं, आपका समाधान संभवतः कमांड लाइन की लंबाई सीमा को पार कर जाएगा , जिससे ls
कई बार आह्वान किया जा सकता है। आपको गलत उत्तर मिल जाएगा, लेकिन आप कभी नहीं जान पाएंगे।
निम्न आदेशों को किसी भी तरह के अजीब फ़ाइल नामों के साथ काम करने की गारंटी है:
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
) उन सेकंडों को समाप्त कर देता है जब से यूनिक्स युग थोड़ा तेज होता है। यूनिक्स के युग के बाद सेड सेकंड को हटा देता है।
अंतिम कमांड बिल्कुल भी रूपांतरण नहीं करता है और पहले दो की तुलना में काफी तेज होना चाहिए। खोज आदेश स्वयं सबसे पुरानी फ़ाइल के माइम को प्रदर्शित नहीं करेगा, इसलिए स्टेट की आवश्यकता है।
यद्यपि स्वीकृत उत्तर और यहां अन्य लोग काम करते हैं, यदि आपके पास एक बहुत बड़ा पेड़ है, तो वे सभी फाइलों के पूरे गुच्छा को सॉर्ट करेंगे।
बेहतर यह होगा कि हम उन्हें सूचीबद्ध कर सकें और सबसे पुराने को ट्रैक कर सकें, बिना किसी क्रम के।
यही कारण है कि मैं इस वैकल्पिक समाधान के साथ आया:
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}'
कमांड समझाया:
इसे चलाना:
~ $ 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}'
ls
स्क्रिप्टिंग के लिए बुरा है क्योंकि इसका आउटपुट मशीनों के लिए नहीं है, आउटपुट स्वरूपण पूरे कार्यान्वयन में भिन्न होता है। जैसा कि आपने पहले ही बताया find
है कि यह स्क्रिप्टिंग के लिए अच्छा है, लेकिन ls
समाधान के बारे में बताने से पहले उस जानकारी को जोड़ना भी अच्छा हो सकता है ।
कृपया ls का उपयोग करें - मैन पेज आपको बताता है कि डायरेक्टरी को कैसे ऑर्डर करना है।
ls -clt | head -n 2
-N 2 है, इसलिए आपको आउटपुट में "कुल" नहीं मिलता है। यदि आप केवल फ़ाइल का नाम चाहते हैं।
ls -t | head -n 1
और अगर आपको सामान्य क्रम में सूची की आवश्यकता है (नवीनतम फ़ाइल प्राप्त करना)
ls -tr | head -n 1
खोजने के लिए उपयोग करने की तुलना में बहुत आसान है, बहुत तेज है, और अधिक मजबूत है - फ़ाइल नामकरण स्वरूपों के बारे में चिंता करने की ज़रूरत नहीं है। यह लगभग सभी प्रणालियों पर भी काम करना चाहिए।
find ! -type d -printf "%T@ %p\n" | sort -n | head -n1
sort -n
।
ऐसा लगता है कि "सबसे पुराने" द्वारा अधिकांश लोगों ने माना है कि आपका मतलब "सबसे पुराना संशोधन समय" था। शायद "सबसे पुराना" की सबसे सख्त व्याख्या के अनुसार, इसे सही किया गया है, लेकिन यदि आप सबसे पुराने पहुंच समय के साथ चाहते हैं , तो मैं सबसे अच्छा उत्तर इस प्रकार संशोधित करूंगा:
find -type f -printf '%A+ %p\n' | sort | head -n 1
ध्यान दें %A+
।
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
दूसरा कॉलम, यानी फ़ाइल नाम प्रदर्शित करता है।
find -type f -printf '%T+ %p\n' | sort | head -1