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

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

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

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

پرسش و پاسخ شماره ۱۸

پرسش و پاسخ شماره ۱۸

چگونه می‌توانم از اعدادی که با صفر شروع می‌شوند مثل 01 و 02 در یک حلقه استفاده کنم؟

به طور معمول، چند روش برای حل مشکل موجود است، هریک با مزایا و معایب خاص خود.

Bash نگارش 4 صفرهای پُرکننده(صفر قبل از عدد) و دامنه آنها را در بسط ابرویش مجاز می‌دارد:

    # Bash 4
    echo {01..10}

    for i in {01..10}; do ...

تمام چاره کارهای دیگر در این صفحه Bash قبل از نگارش 4.0، یا پوسته‌های غیر از Bash را فرض خواهد نمود.

اگر تعداد اعداد زیاد نیست، بسط ابرو می‌تواند به کار برود:

    # Bash
    for i in 0{1,2,3,4,5,6,7,8,9} 10
    do
        echo $i
    done

در Bash نگارش 3، می‌توانید دامنه‌ها را داخل بسط ابرو به کار ببرید(اما صفر پُرکننده را خیر). بنابراین همان کارمی‌تواند به طور مختصرتری به این شکل انجام بشود:

    # Bash 3
    for i in 0{1..9} 10
    do
        echo $i
    done

مثال دیگر، برای خروجی 0000 تا 0034:

    # Bash 3
    for i in {000{0..9},00{10..34}}
    do
        echo $i
    done

    # .ابروهای خارجی فقط به جای اضافه کردن آنها یکی پس از دیگری است‎
    # :استفاده از بسط را اجازه می‌دهد، به طور نمونه، مانند این
    wget 'http://foo.com/adir/thepages'{000{0..9},00{10..34}}'.html'

برخی شاید روش سریع و نامنزه زیر را ترجیح بدهند(برای تولید "000" تا "015"):

    # Bash 3
    for i in {1000..1015}
    do
      echo "${i:1}"    # یا "${i#1}" 
    #  (مترجم: در اینجا از بسط پارامتر استفاده گردیده است) 
    done

این برای توالی وسیع کسل کننده می‌شود، اما روشهای دیگری نیز وجود دارد. اگر فرمان printf را(که یک فرمان داخلی Bash است و استاندارد POSIX نیز هست) دارید، می‌تواند برای قالب‌بندی عدد به کار برود:

    # Bash
    for ((i=1; i<=10; i++))
    do
        printf "%02d " "$i"
    done

همچنین، چون printf به طور ضمنی حلقه است، اگر شناسه‌هایی غیر از مشخص کننده قالب داده شده باشد، می‌توانید به طورهنگفتی این را مختصر نمایید:

   # Bash 3
   printf "%03d\n" {1..300}

اگر از قبل مقدار شروع و خاتمه را نمی‌دانید:

   # Bash 3
   #  متغیرهای شامل عدد صحیح می‌باشند end و start
   eval printf '"%03d\n"' {$start..$end}

فرمان eval در اینجا لازم است، زیرا نمی‌توانید در بسط ابرو متغیرها را داشته باشید --فقط ثابت‌ها.نقل‌قولهای اضافی را eval لازم دارد برای اینکه‎ \n‎ ما به یک n تغییر نکند. قدر مسلم روش eval راه حل شلوغی است، لطفاً برای مقاصد خطیر به جای آن از حلقه for استفاده کنید.

در پوسته Korn فرمان typeset دارای گزینه‌ای برای تعیین تعداد ارقام عدد می‌باشد:

    # Korn
    $ typeset -Z3 i=4
    $ echo $i
    004

اگر فرمان ‎seq(1)‎ در دسترس باشد( بخشی از‎ GNU sh-utils/coreutils‎ می‌باشد)، می‌توانید به این شکل از آن استفاده کنید:

    seq -w 1 10

یا، برای تعداد ارقام دلخواه همراه با صفرهای پشت عدد(در اینجا: 3):

    seq -f "%03g" 1 10

با ترکیب printf با ‎seq(1)‎، می‌توانید موردی مانند این را انجام بدهید:

   # POSIX shell, GNU utilities
   printf "%03d\n" $(seq 300)

(که شاید اگر از Bash استفاده نمی‌کنید، اما ‎ seq(1)‎ را دارید و نگارش ‎seq(1)‎ شما فاقد مشخص کننده قالب سَبک printf است، این روش مفید باشد. یک مجموعه عجیبی از محدودیت‌هامی‌باشد، اماگمان می‌کنم به طور نظری ممکن باشد. چون seq ابزار خارجی غیر استانداردی است، خوب است انتخاب‌های شما باز باشد.)

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

بعضی سیستمهای مشتق شده از BSD در عوض‎ seq(1)‎دارای ‎ jot(1)‎ می‌باشند. مطابق رسم خیلی خوب یونیکس، این یک ترکیب دستوری کاملاً ناسازگاری دارد:

   # POSIX shell, OpenBSD et al.
   printf "%02d\n" $(jot 10 1)

   # Bourne shell, OpenBSD (at least)
   jot -w %02d 10 1

سرانجام، مثال ذیل که با هرپوسته مشتق شده از شل Bourne (که هم expr و هم sed را دارد) با سه بایت برای هر عدد در هر سطر و صفر قبل از عدد در صورت لزوم، کار می‌کند:

   # Bourne
   i=0
   while test $i -le 10
   do
       echo "00$i"
       i=`expr $i + 1`
   done |
       sed 's/.*\(...\)$/\1/g'

در این مثال، تعداد '.' داخل پرانتزها در فرمان sed تعیین می‌کند چند بایت از فرمان echo (در انتهای هر سطر) حفظ و چاپ خواهد شد.

اما اگر به راستی می‌خواهید به یک فرمان خارجی یونیکس استناد کنید، در درجه اول می‌توانید تمام آن را به خوبی با awk انجام بدهید:

   # Bourne
   # شامل یک عدد صحیح است count متغیر
   awk -v count="$count" 'BEGIN {for (i=1;i<=count;i++) {printf("%03d\n",i)} }'

   #  بی‌فایده awk با سولاریس سالخورده و  Bourn
   awk "BEGIN {for (i=1;i<=$count;i++) {printf(\"%03d\\n\",i)} }"


اکنون، چون دلیل شماره یک پرسیدن این سؤال برای بارگیری تصویرها به طور انبوه است، می‌توانید مثالهای فوق را با ‎ xargs(1)‎ و ‎wget(1)‎ برای واکشیدن فایلها به کار ببرید:

   almost any example above | xargs -i% wget $LOCATION/%

فرمان ‎ xargs -i%‎ در هر نوبت سطری از ورودی را می‌خواند، و % انتهای فرمان را با ورودی تعویض می‌کند.

یا، مثال ساده‌تر که به کاربردن حلقه forاست:

   # Bash 3
   for i in {1..100}; do
      wget "$prefix$(printf %03d $i).jpg"
      sleep 5
   done

یا، برای اجتناب از پوسته‌های فرعی( bash نگارش 3.1 لازم دارد):

   # Bash 3.1
   for i in {1..100}; do
      printf -v n %03d $i
      wget "$prefix$n.jpg"
      sleep 5
   done


CategoryShell

پرسش و پاسخ 18 (آخرین ویرایش ‎ 2012-02-01 16:00:55 ‎ توسط GreyCat)

نظرات 0 + ارسال نظر
ایمیل شما بعد از ثبت نمایش داده نخواهد شد