আউটপুট পার্সিং 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 সাল থেকে সেকেন্ড", ভগ্ন সেকেন্ড সহ নির্দেশ করে।
স্থানটি নিছক একটি স্বেচ্ছাসেবী সীমারেখা। ফাইলটির পুরো পথটি যাতে আমরা পরে এটি উল্লেখ করতে পারি, এবং এনইউএলএল চরিত্রটি একটি টার্মিনেটর কারণ এটি কোনও ফাইলের নামের একটি অবৈধ চরিত্র এবং সুতরাং আমাদের নিশ্চিতভাবে জানতে দেয় যে আমরা পাথের শেষের দিকে পৌঁছেছি ফাইল।
আমি অন্তর্ভুক্ত করেছি 2>/dev/nullযাতে ব্যবহারকারীর অ্যাক্সেসের অনুমতি না থাকা ফাইলগুলি বাদ দেওয়া হয় তবে তাদের বাদ দেওয়া সংক্রান্ত ত্রুটি বার্তাগুলি দমন করা হয়।
findকমান্ডের ফলাফলটি বর্তমান ডিরেক্টরিতে থাকা সমস্ত ডিরেক্টরিগুলির একটি তালিকা। তালিকাটি পাইপ করা হয়েছে sortযাতে নির্দেশ দেওয়া হয়:
-z নিউলাইন পরিবর্তে লাইন টার্মিনেটর চরিত্র হিসাবে NULL আচরণ করুন।
-n সংখ্যা অনুসারে বাছাই করুন
যেহেতু সেকেন্ড -১ 1970০ since সর্বদা উপরে চলে যায় আমরা সেই ফাইলটি চাই যার টাইমস্ট্যাম্পটি সবচেয়ে ছোট সংখ্যা ছিল। এর থেকে প্রথম ফলাফলটি sortহবে সর্বনিম্ন সংখ্যাযুক্ত টাইমস্ট্যাম্প যুক্ত লাইন। যা যা অবশিষ্ট রয়েছে তা ফাইলের নাম তোলা।
ফলাফল find, sortপাইপলাইন মাধ্যমে পাস করা হয়েছে প্রক্রিয়া প্রতিকল্পন করতে whileযেখানে এটি পড়া হয় যেমন যদি এটা stdin একটি ফাইল ছিল। whileপরিবর্তে readইনপুট প্রক্রিয়া করার জন্য অনুরোধ ।
প্রসঙ্গে readআমরা IFSভেরিয়েবলটিকে কিছুতেই সেট করি নি, যার অর্থ হ'ল স্পেস স্পেসটি অনুচিতভাবে ডিলিমিটার হিসাবে ব্যাখ্যা করা হবে না। readবলা হয় -r, যা পালানোর প্রসারকে অক্ষম করে এবং -d $'\0'যা আমাদের find, sortপাইপলাইন থেকে আউটপুটটির সাথে মিল রেখে শেষ প্রান্তের ডিলিমিটারকে NULL করে তোলে ।
ডেটার প্রথম খণ্ড, যে প্রাচীনতম ফাইল পাথ তার টাইমস্ট্যাম্প এবং ব্যবধানের দ্বারা পূর্বে প্রতিনিধিত্ব করে, পরিবর্তনশীল মধ্যে পড়া হয় line। এর পরে, প্যারামিটার প্রতিস্থাপনটি এক্সপ্রেশন দিয়ে ব্যবহৃত হয় #*, যা স্ট্রিংয়ের শুরু থেকে শুরু করে প্রথম স্থান পর্যন্ত সমস্ত অক্ষরকে কিছু না করে কেবল স্থান দেয়। এটি পরিবর্তনের টাইমস্ট্যাম্পটিকে সরিয়ে দেয়, কেবলমাত্র ফাইলের পুরো পথ ছেড়ে।
এই মুহুর্তে ফাইলের নামটি সংরক্ষণ করা হয় $fileএবং আপনি এটির সাথে নিজের পছন্দ মতো কিছু করতে পারেন। আপনার সাথে কিছু যখন করছেন সমাপ্ত করছি বিবৃতি ইচ্ছা লুপ এবং কমান্ড পরবর্তী খণ্ড এবং পরবর্তী ফাইলের নাম আহরণের আবার মৃত্যুদন্ড কার্যকর করা হবে।$filewhileread
একটি সহজ উপায় আছে না?
না। সহজ উপায়গুলি বগি।
আপনি ব্যবহার করেন তাহলে 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 এবং Павел Танков এই উত্তর উন্নতি জন্য।