پرسش و پاسخ شماره ۴۴ - آموزش اسکریپت نویسی
X
تبلیغات
رایتل

آموزش اسکریپت نویسی

آموزش اسکریپت نویسی پوسته گنو-لینوکس

#!/bin/bash

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

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

چطور می‌توانم نوار پیشروی ایجاد کنم؟ چگونه می‌توانم موقع کپی یا انتقال فایلها، نمایشگر پیشروی را ببینم؟

آسان‌ترین روش افزودن نوار پیشرفت به اسکریپت خودتان، استفاده از ‎ dialog --gauge‎ است. در اینجا مثالی آورده‌ایم که متکی به ویژگی‌های BASH می‌باشد:

# Bash
# .در شاخه جاری را پردازش می‌کند *.zip تمام فایلهای
files=(*.zip)
dialog --gauge "Working..." 20 75 < <(
   n=${#files[*]}; i=0
   for f in "${files[@]}"; do
   # قرار بدهید "sleep 1"‎ را قرار بدهید، برای تست ‎"$f"‎ در اینجا دستورات پردازش ‎
      echo $((100*(++i)/n))
   done
)

این هم توضیح آن که چکار می‌کند:

  • یک آرایه به نام files با تمام فایلهایی که می‌خواهیم پردازش کنیم، دارای عضو می‌شوند.

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

  • پردازش حلقه روی آرایه تکرار می‌شود.
  • هر نوبت که فایلی پردازش می‌شود، شمارشگر(i) را افزایش می‌دهد، و درصد تکمیل را در خروجی می‌نویسد.

برای مثالهای بیشتری از کاربرد dialog، پرسش و پاسخ شماره 40 را ببینید.

نوار پیشرفت ساده‌ای نیز می‌تواند بدون استفاده از dialog برنامه ریزی بشود. رویکردهای متفاوت زیادی برای این مورد وجود دارد که بستگی به نوع نمایشی دارد که شما در جستجوی آن می‌باشید.

یک رویکرد سنتی چرخنده است که یک پاره خط در حال دوران را برای دلالت بر مشغول بودن نمایش می‌دهد. این در اصل میزان پیشرفت نیست چون اطلاعاتی در مورد آنکه چطور برنامه به تکمیل شدن نزدیک می‌شود، ارائه نمی‌کند.

مرحله بعدی نمایش یک مقدار عددی بدون حرکت در صفحه نمایش است. استفاده از سطر نورد برای حرکت نشانگر جهت تبدیل شدن به یک سطر(در ترمینال گرافیکی، نه یک دورنگار...) و ننوشتن سطر جدید تا به پایان رسیدن پردازش:

i=0
while ((i < 100)); do
  printf "\r%3d%% complete" $i
  ((i += RANDOM%5+2))
  # را از جایی معنی‌دار دریافت می‌کنیم i البته در زندگی واقعی، ما‎
  sleep 1
done
echo

نکته در اینجا تعیین کننده قالب ‎%3d‎ در printf است. استفاده از فیلد با عرض ثابت برای نمایش اعداد اهمیت دارد، مخصوصاً اگر شمارش معکوس انجام شود(اول 10 و بعد 9 نمایش داده شود). البته ما در اینجا شمارش رو به بالا انجام دادیم، اما به طور عمومی همیشه به این حالت نیست. اگر فیلد با عرض ثابت مطلوب نیست، آنوقت چاپ یک گروه فاصله در انتها می‌تواند به زدودن هر گونه درهم‌برهمی با سطرهای قبلی کمک کند.

اگر بجای یک عدد، یک نوار واقعی مورد نظر باشد، آنوقت شاید شخصی با استفاده از کاراکترهای اسکی آن را رسم کند:

bar="=================================================="
barlength=${#bar}
i=0
while ((i < 100)); do
  # .تعداد قطعات نوار برای رسم کردن
  n=$((i*barlength / 100))
  printf "\r[%-${barlength}s]" "${bar:0:n}"
  ((i += RANDOM%5+2))
  # را از جایی معنی‌دار دریافت می‌کنیم i البته در زندگی واقعی، ما‎
  sleep 1
done
echo

بدیهی است هر کس می‌تواند نواری با طول متفاوت، یا ترکیبی ازمجموعه کاراکترهای متفاوت را انتخاب کند، به عنوان مثال، می‌توانید یک نوار پیشروی رنگی داشته باشید

files=(*)
width=${COLUMNS-$(tput cols)}
rev=$(tput rev)

n=${#files[*]}
i=0
printf "$(tput setab 0)%${width}s\r"
for f in "${files[@]}"; do
   # قرار بدهید "sleep 1"‎ را قرار بدهید، برای تست ‎"$f"‎ در اینجا دستورات پردازش 
   printf "$rev%$((width*++i/n))s\r" " "
done
tput sgr0
echo

هنگام کپی یا انتقال فایلها

نمی‌توانید با‎ cp(1)‎ نمایشگر پیشروی به دست آورید، اما شما می‌توانید :

  • یا خودتان با ابزاری از قبیل pv یا clpbar یکی بسازید

  • یا ابزار دیگری به کار ببرید، به عنوان مثال vcp.

شاید بخواهید از ‎ pv(1)‎ استفاده کنید چون برای بسیاری از سیستم‌ها به صورت بسته‌بندی شده موجود است. در این حالت، اگر تابع یا اسکریپتی برای پوشاندن آن ایجاد نمایید، مناسب است.

برای مثال:

pv "$1" > "$2/${1##*/}"

این فاقد کنترل خطا می‌باشد و از انتقال فایلها پشتیبانی می‌کند.

همچنین می‌توانید از rsync استفاده کنید:

rsync -avx --progress --stats "$1" "$2"

لطفاً توجه نمایید هر دفعه که rsync وارد یک دایرکتوری می‌شود و فایلهای کمتر یا بیشتر از مورد انتظارش پیدا می‌کند، تعداد کل فایلها می‌تواند تغییر نماید، اما حداقل بیش از cp مطلع است. پیشرفت Rsync برای انتقالهای بزرگ با تعداد فایل کم مناسب است.


CategoryShell

پرسش و پاسخ 44 (آخرین ویرایش ‎ 2010-06-25 20:12:14 ‎ توسط MatthiasPopp)