آموزش‌های خط فرمانی

این وبلاگ تلاش می‌کند گامی در حد بضاعت در جهت آموزش خط فرمان و اسکریپت‌نویسی پوسته گنو-لینوکس بردارد.

آموزش‌های خط فرمانی

این وبلاگ تلاش می‌کند گامی در حد بضاعت در جهت آموزش خط فرمان و اسکریپت‌نویسی پوسته گنو-لینوکس بردارد.

جدیدترین یا قدیمی‌ترین فایل در دایرکتوری


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

این صفحه باید با پرسش و پاسخ شماره ۳ ادغام می‌شد.

پاسخ ‎ls -t | head -1‎ که فوراً به ذهن می‌رسد، اشتباه است، به علت آنکه تجزیه خروجی ls نا امن است، در عوض، باید حلقه‌ای ایجاد نموده و نشانه‌های زمان را مقایسه کنید:

# Bash
files=(*) newest=${files[0]}
for f in "${files[@]}"; do
  if [[ $f -nt $newest ]]; then
    newest=$f
  fi
done

آنوقت جدیدترین فایل(براساس زمان ویرایش فایل) را در ‎$newest‎ خواهید داشت. برای به دست آوردن قدیمی‌ترین فایل، به سادگی ‎-nt‎ را به ‎-ot‎ تغییر بدهید(برای لیستی از عملگرها ‎help test‎ را ببینید)، و البته برای اجتناب از تداخل، نام متغیرها را تغییر بدهید.

Bash وسیله‌ای غیر از mtime برای مقایسه نشانه‌های زمان فایل ندارد، بنابراین اگر بخواهید(برای مثال) آخرین فایل دستیابی شده (جدیدترین توسط atime) را به دست بیاورید، می‌باید از فرمان خارجی ‎stat(1)‎ (اگر آن را دارید) یا از فرمان finfo داخلی قابل بارگیری (اگر می‌توانید دستورات داخلی را بارگیری کنید) کمک بگیرید.

این هم مثالی از کاربرد stat از ‎coreutils 6.10‎ گنو (متأسفانه، حتی در میان سیستم‌های لینوکس، ترکیب دستوری فرمان stat سازگار نیست) برای به دست آوردن آخرین فایل دستیابی شده. ( در این نگارش، ‎%X‎ آخرین زمان دستیابی است.)

# Bash, GNU coreutils
newest= newest_t=0
for f in *; do
  t=$(stat --format=%X -- "$f")   # atime
  if ((t > newest_t)); then
    newest_t=$t
    newest=$f
  fi
done

این روش همچنین دارای اشکال تولید مثل یک برنامه خارجی برای هر فایل داخل دایرکتوری می‌باشد، پس، این روش فقط در صورت ضرورت باید به کار برود. برای به دست آوردن قدیمی‌ترین فایل با استفاده از این روش، یا باید ‎oldest_t‎ را با بیشترین مقدارِ ممکنِ نشانه زمان(گزاره مهارت‌آمیز، مخصوصاً چنانکه ما سال 2038 را پیشنهاد می‌کنیم)، یا با نشانه زمان اولین فایل در دایرکتوری، چنانکه در مثال اول دیدیم، مقداردهی کنید.

این هم یک راه‌حل دیگر با تولیدمثل یک برنامه خارجی، اما موافق با posix:

# posix
unset newest
for f in ./*; do
  # در اولین دور حلقه newest تنظیم متغیر‎
  newest=${newest-$f} 
  #  در find برای اجتناب از سیر نزولی در دایرکتوری‌ها می‌باشد، وضعیت خروج ‎-prune‎‎
  #  .اینجا بیفایده است، ما خروجی را بررسی می‌کنیم 
  if [ "$(find "$f" -prune -newer "$newest")" ]; then 
    newest=$f
  fi
done

مثال: چگونه غیر از آخرین دایرکتوری، همگی را حذف کنیم. (توجه، زمان ویرایش دایرکتوری زمان آخرین عملیاتی است که در آن دایرکتوری تغییر ایجاد می‌کند -- یعنی آخرین ایجاد، حذف، یا تغییرنام فایل در آن.)

 $ cat clean-old 
 dirs=(enginecrap/*/) newest=${dirs[0]}
 for d in "${dirs[@]}"
  do if [[ $d -nt $newest ]]
     then newest=$d
     fi
  done

 for z in "${dirs[@]}"
  do if [[ "$z" != "$newest" ]]
     then rm -rf "$z"
     fi
  done
 $ for x in 20101022 20101023 200101025 20101107 20101109; do mkdir enginecrap/"$x";done
 $ ls enginecrap/
 200101025       20101022        20101023        20101107        20101109
 $ ./clean-old 
 $ ls enginecrap/
 20101109


CategoryShell

پرسش و پاسخ 99 (آخرین ویرایش ‎2013-03-18 21:54:17‎ توسط geirha)


نظرات 1 + ارسال نظر
سعید رسولی جمعه 19 مهر‌ماه سال 1392 ساعت 07:19 ب.ظ http://saeedgnu.blog.ir

ولی همون ls -t1 | head توی نیازهای روزمره جواب میده. آخه کدوم دیوانه‌ای توی اسم فایل کاراکتر سر خط میذاره؟ :D
اگه قرار باشه اینقدر دقیق و سخت‌گیر باشیم که از ls توی اسکریپت استفاده نکنیم، من ترجیج میدم اسکریپت رو با پایتون بنویسم که تمیزتر و زیباتر دربیاد.
بش محدودیت‌های خودش رو داره و بیشتر برای برنامه‌های تک‌منظوره مناسب هست نه برنامه‌های چندمنظوره و پرکاربر.

به هر حال، به اطلاعاتم در مورد بش اضافه شد. ممنون

ایمیل شما بعد از ثبت نمایش داده نخواهد شد