منبع اصلی نوشتار زیر در این لینک قرار دارد

پرسش و پاسخ شماره ۳


پرسش و پاسخ‌های رایج Bash  در Greg\'s Wiki

پرسش و پاسخ شماره ۳

چطور می‌توانم آخرین(جدیدترین، قدیمی‌ترین، مسن‌ترین) فایل در یک دایرکتوری را پیدا کنم؟

راه حل اغوا کننده، استفاده از ls برای برونداد نام فایلهای موجود، و اخذ اولین نتیجه، می‌باشد. به طور عادی رویکرد ls نمی‌تواند مناسب باشد و به خاطر احتمال برخورد با کارکترهای اختیاری(شامل سطر جدید) موجود در نام فایلها، هرگز نباید در اسکریپت‌ها به کار برود. بنابراین، به شیوه‌های دیگری برای سنجش فوق داده‌های(metadata) فایل، نیاز داریم.

بیشترین مورد نیاز، برای یافتن قدیم‌ترین و جدیدترین فایل ویرایش شده در دایرکتوری جاری، می‌باشد. Bash و همه نگارش‌های متنوع ksh می‌توانند زمانهای ویرایش(mtime) را با استفاده از عملگرهای ‎-nt‎ و ‎-ot‎ در عبارت شرطی دستور مرکب، مقایسه کنند:

# Bash/ksh
unset -v latest
for file in \"$dir\"/*; do
  [[ $file -nt $latest ]] && latest=$file
done

یا برای یافتن قدیمی‌ترین:

# Bash/ksh
unset -v oldest
for file in \"$dir\"/*; do
  [[ -z $oldest || $file -ot $oldest ]] && oldest=$file
done

به خاطر داشته باشید که mtime در مورد دایرکتوری‌ها، مربوط به آن شاخه‌ای است، که آخرین افزودن، حذف یا تغییر نام فایل در آن انجام شده است. همچنین توجه کنید که ‎ -nt‎ و ‎-ot‎ توسط POSIX test تعریف نشده‌اند، هر چند بسیاری از پوسته‌ها ازقبیل dash به طریقی آنها را در خود دارند. شل‌های غیرهم‌گروه با پوسته bourne، دارای عملگرهای مشابهی برای مقایسه atime یا ctime می‌باشند، همچنین شاید برای آنها نیاز به برنامه‌های خارجی باشد، به هرحال، فراهم نمودن خروجی، که بتواند به طور سالم تجزیه شود، یا مدیریت خروجی مذکور، بدون استفاده از ویژگی‌های غیراستاندارد، تقریباً در شل غیر ممکن است .

اگر معیار مرتب‌سازی غیر از «قدیمی‌ترین» و «جدیدترین» فایل باشد، ممکن است فرمان find و sort گنو، همراه باهم برای تولید لیست مرتب شده‌ای از نام فایلها و نشانه‌های زمان( timestamps)، که با کاراکترهای تهی جدا شده‌اند، به کاربرود. البته، این به طور بازگشتی عمل می‌کند(عملگر ‎-maxdepth‎ فرمان find گنو می‌تواند از آن پیش‌گیری کند)، این هم تعدادی از امکاناتی که در صورت لزوم می‌تواند برای استفاده atime یا ctime، یا مرتب‌سازی معکوس، ویرایش بشوند:

# Bash + GNU find + GNU sort (To the precision possible on the given OS, but returns only one result)
IFS= read -r -d \'\' latest \\
  < <(find \"$dir\" -type f -printf \'%T@ %p\\0\' | sort -znr)
latest=${latest#* }   # remove timestamp + space

# GNU find + Bash w/ arrays (To the nearest 1s, using an undocumented \"find -printf\" format (%Ts).)
while IFS= read -rd \'\' \'latest[$(read -rd \"\" y; echo $y)]\'
    do :
done < <(find \"$dir\" -type f -printf \'%p\\0%Ts\\0\')
latest=${latest[-1]}

# GNU stat + Bash /w arrays (non-recursive w/o globstar, to the nearest 1s)
while IFS= read -rd \'\' \'latest[$(read -rd \"\" y; echo $y)]\'
    do :
done < <(stat \'--printf=%n\\0%Y\\0\' \"$dir\"/*)
latest=${latest[-1]}

یکی از اشکالات این رویکردها آنست که تمام لیست ذخیره می‌شود، در حالیکه حقیقتاً تکرار روی تمام لیست برای یافتن نشانه زمان(timestamp) حداقل و حداکثر(با فرض آنکه فقط یک فایل را می‌خواهیم) سریعتر خواهد بود، به هرحال، بسته به اندازه کار اشکال الگوریتم مرتب‌سازی در مقایسه با دردسر استفاده از یک پوسته شاید قابل گذشت باشد.

# Bash + GNU find
unset -v latest time
while IFS= read -r -d \'\' line; do
  t=${line%% *} t=${t%.*}   # truncate fractional seconds
  ((t > time)) && { latest=${line#* } time=$t; }
done < <(find \"$dir\" -type f -printf \'%T@ %p\\0\')

خوانندگانی که این سؤال را به منظور معکوس نمودن ترتیب فایلهای ثبت وقایع(log) خود پرسیده‌اند شاید در عوض مایل باشند به‎ logrotate(1)‎ نگاه کنند، اگر سیستم عامل آنها آنرا فراهم نموده باشد.


CategoryShell

پرسش و پاسخ 3 (آخرین ویرایش ‎ 2012-07-19 04:03:35 ‎ توسط ormaaj)




به سیاره لینوکس امتیاز دهید

به اين صفحه امتياز دهيد