के उत्पादन में पार्स 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
और आप इसके साथ कुछ भी कर सकते हैं। आप के साथ कुछ जब कर समाप्त कर देते हैं बयान इच्छा पाश और आदेश अगले हिस्सा और अगले फ़ाइल नाम निकालने फिर से निष्पादित किया जाएगा,।$file
while
read
वहाँ एक सरल तरीका नहीं है?
नहीं। सरल तरीके छोटी गाड़ी हैं।
यदि आप या (या कुछ भी ) का उपयोग ls -t
और पाइप करते हैं, तो आप फ़ाइल नामों में नईलाइन्स वाली फ़ाइलों पर टूट जाएंगे। यदि आप नाम में व्हॉट्सएप के साथ फाइल करते हैं, तो इससे टूटना होगा। यदि आप नाम में नई अनुगामी के साथ फाइल करते हैं, तो इससे टूटना होगा। यदि आप बिना तो आप उनके नाम पर व्हाट्सएप के साथ फाइलों पर टूट पड़ेंगे।head
tail
mv $(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 और Павел Танков का धन्यवाद ।