के उत्पादन में पार्स lsहै विश्वसनीय नहीं ।
इसके बजाय, findफ़ाइलों का पता लगाने और sortटाइमस्टैम्प द्वारा उन्हें ऑर्डर करने के लिए उपयोग करें। उदाहरण के लिए:
while IFS= read -r -d $'\0' line ; do
file="${line#* }"
# do something with $file here
done < <(find . -maxdepth 1 -printf '%T@ %p\0' \
2>/dev/null | sort -z -n)
यह सब क्या कर रहा है?
सबसे पहले, findकमांड वर्तमान निर्देशिका में सभी फ़ाइलों और निर्देशिकाओं का पता लगाता है ( .), लेकिन वर्तमान निर्देशिका की उपनिर्देशिकाओं में नहीं ( -maxdepth 1), फिर प्रिंट करता है:
- एक टाइमस्टैम्प
- एक स्थान
- फ़ाइल के सापेक्ष पथ
- एक पूर्ण चरित्र
टाइमस्टैम्प महत्वपूर्ण है। %T@के लिए फॉर्मेट स्पेसिफायर -printfमें नीचे टूट जाता है T, जो फ़ाइल (mtime) और "अंतिम संशोधन समय" इंगित करता है @, जो "1970 के बाद से सेकंड", आंशिक सेकंड सहित इंगित करता है।
अंतरिक्ष केवल एक मनमाना परिसीमन है। फ़ाइल का पूर्ण पथ ऐसा है जिसे हम बाद में संदर्भित कर सकते हैं, और NULL वर्ण एक टर्मिनेटर है क्योंकि यह फ़ाइल नाम में एक अवैध वर्ण है और इस प्रकार हमें यह सुनिश्चित करने के लिए देता है कि हम पथ के अंत तक पहुँच गए हैं फ़ाइल।
मैंने 2>/dev/nullइसलिए शामिल किया है कि जिन फ़ाइलों को उपयोगकर्ता को एक्सेस करने की अनुमति नहीं है, उन्हें बाहर रखा गया है, लेकिन उन्हें बाहर करने के बारे में त्रुटि संदेश दबाए जाते हैं।
findआदेश का परिणाम वर्तमान निर्देशिका में सभी निर्देशिकाओं की एक सूची है। सूची को पाइप किया जाता है, sortजिसे निम्न निर्देश दिया गया है:
-z न्यूलाइन की बजाए NULL को लाइन टर्मिनेटर कैरेक्टर मानें।
-n संख्यात्मक रूप से क्रमबद्ध करें
चूंकि सेकंड -1920 हमेशा ऊपर जाता है, हम चाहते हैं कि फ़ाइल जिसकी टाइमस्टैम्प सबसे छोटी संख्या थी। से पहला परिणाम sortसबसे छोटी संख्या वाली टाइमस्टैम्प वाली लाइन होगी। वह सब कुछ फ़ाइल नाम निकालने के लिए है।
के परिणाम find, sortपाइपलाइन को प्रक्रिया प्रतिस्थापन के माध्यम से पारित किया जाता है whileजहां इसे पढ़ा जाता है जैसे कि यह स्टडिन पर एक फ़ाइल थी। whileबदले readमें इनपुट को संसाधित करने के लिए आमंत्रित करता है।
readहम IFSकुछ भी नहीं करने के लिए चर सेट के संदर्भ में , जिसका अर्थ है कि व्हाट्सएप को अनुचित रूप से एक सीमांकक के रूप में व्याख्या नहीं किया जाएगा। readबताया जाता है -r, जो भागने के विस्तार को अक्षम करता है, और -d $'\0'जो हमारे find, sortपाइपलाइन से आउटपुट का मिलान करते हुए, अंतिम सीमांकक NULL बनाता है ।
डेटा का पहला हिस्सा, जो अपने टाइमस्टैम्प और एक स्थान से पहले के सबसे पुराने फ़ाइल पथ का प्रतिनिधित्व करता है, चर में पढ़ा जाता है line। अगला, पैरामीटर प्रतिस्थापन का उपयोग अभिव्यक्ति के साथ किया जाता है #*, जो केवल स्ट्रिंग की शुरुआत से लेकर अंतरिक्ष सहित पहली जगह तक सभी पात्रों को प्रतिस्थापित करता है, कुछ भी नहीं के साथ। यह संशोधन टाइमस्टैम्प को बंद कर देता है, जिससे फ़ाइल में केवल पूर्ण पथ रह जाता है।
इस बिंदु पर फ़ाइल का नाम संग्रहीत है $fileऔर आप इसके साथ कुछ भी कर सकते हैं। आप के साथ कुछ जब कर समाप्त कर देते हैं बयान इच्छा पाश और आदेश अगले हिस्सा और अगले फ़ाइल नाम निकालने फिर से निष्पादित किया जाएगा,।$filewhileread
वहाँ एक सरल तरीका नहीं है?
नहीं। सरल तरीके छोटी गाड़ी हैं।
यदि आप या (या कुछ भी ) का उपयोग ls -tऔर पाइप करते हैं, तो आप फ़ाइल नामों में नईलाइन्स वाली फ़ाइलों पर टूट जाएंगे। यदि आप नाम में व्हॉट्सएप के साथ फाइल करते हैं, तो इससे टूटना होगा। यदि आप नाम में नई अनुगामी के साथ फाइल करते हैं, तो इससे टूटना होगा। यदि आप बिना तो आप उनके नाम पर व्हाट्सएप के साथ फाइलों पर टूट पड़ेंगे।headtailmv $(anything)mv "$(anything)"read-d $'\0'
शायद विशिष्ट मामलों में आप यह सुनिश्चित करने के लिए जानते हैं कि एक सरल तरीका पर्याप्त है, लेकिन आपको लिपियों में कभी भी इस तरह की धारणाएं नहीं लिखनी चाहिए यदि आप ऐसा करने से बच सकते हैं।
समाधान
#!/usr/bin/env bash
# move to the first argument
dest="$1"
# move from the second argument or .
source="${2-.}"
# move the file count in the third argument or 20
limit="${3-20}"
while IFS= read -r -d $'\0' line ; do
file="${line#* }"
echo mv "$file" "$dest"
let limit-=1
[[ $limit -le 0 ]] && break
done < <(find "$source" -maxdepth 1 -printf '%T@ %p\0' \
2>/dev/null | sort -z -n)
जैसे कॉल करें:
move-oldest /mnt/backup/ /var/log/foo/ 20
से सबसे पुरानी 20 फ़ाइलों को स्थानांतरित करने के /var/log/foo/लिए /mnt/backup/।
ध्यान दें कि मैं फ़ाइलों और निर्देशिकाओं सहित हूं । फ़ाइलों के लिए केवल जोड़ने -type fके लिए findमंगलाचरण।
धन्यवाद
इस उत्तर में सुधार के लिए enzotib और Павел Танков का धन्यवाद ।