حلقه while بی نهایت در یک اسکریپت BASH. BASH: شرح حلقه‌های for، while، while و نمونه‌هایی از استفاده مثال: جستجوی فایل‌های اجرایی


نویسنده: پل کابوت
تاریخ انتشار: 16 اکتبر 2014
ترجمه: A. Panin
تاریخ ترجمه: 21 دسامبر 2014

فصل 22. حلقه ها در اسکریپت ها

دستور تست

دستور تست به شما امکان می دهد درست یا نادرست بودن یک عبارت را تعیین کنید. بیایید با آزمایش اینکه آیا مقدار عدد صحیح 10 بزرگتر از عدد صحیح 55 است شروع می کنیم. $ test 10 -gt 55 ; اکو $؟ 1 دلار

اگر عبارت نادرست باشد، دستور تست 1 را برمی گرداند. و همانطور که در مثال زیر مشاهده خواهید کرد، اگر عبارت درست ارزیابی شود، دستور test 0 را برمی گرداند. $ test 56 -gt 55 ; اکو $؟ $0

اگر با رشته های true و false راحت تر کار می کنید، می توانید مطابق شکل زیر از دستور test استفاده کنید. $ تست 56 -gt 55 && echo true || echo false true $ test 6 -gt 55 && echo true || پژواک غلط غلط

دستور تست را می توان با براکت ها نیز جایگزین کرد، بنابراین دستورات در مثال زیر دقیقاً مشابه دستورات مثال بالا هستند. $ [ 56 -gt 55 ] && echo true || echo false true $ [ 6 -gt 55 ] && echo true || پژواک غلط غلط

در زیر نمونه هایی از اجرای برخی از چک ها آورده شده است. برای بررسی کلی به صفحه تست مرد مراجعه کنید ویژگی های اضافیاجرای بررسی های مختلف [ -d foo ] آیا دایرکتوری foo وجود دارد؟ [ -e bar ] آیا فایل نوار وجود دارد؟ [ "/etc" = $PWD ] آیا /etc معادل مقدار $PWD است؟ [ $1 != "secret" ] آیا مقدار پارامتر اول اسکریپت با رشته مخفی متفاوت است؟ [ 55 -lt $bar ] آیا مقدار صحیح 55 کمتر از مقدار $bar است؟ [$foo -ge 1000] آیا مقدار $foo بزرگتر یا مساوی با مقدار صحیح 1000 است؟ ["abc"< $bar ] Будет ли строка abc расположена выше значения переменной $bar в списке после сортировки? [ -f foo ] Является ли foo обычным файлом? [ -r bar ] Является ли bar فایل قابل خواندن? [foo -nt bar] آیا foo جدیدتر از نوار است؟ [ -o nounset ] آیا گزینه Nounset shell فعال است؟

اپراتورهای چک را می توان با عملگرهای مربوط به ترکیب کرد عملیات منطقی"AND" و "OR". paul@RHEL4b:~$ [ 66 -gt 55 -a 66 -lt 500 ] && echo true || echo false true paul@RHEL4b:~$ [ 66 -gt 55 -a 660 -lt 500 ] && echo true || echo false false paul@RHEL4b:~$ [ 66 -gt 55 -o 660 -lt 500 ] && echo true || پژواک غلط درست است

پرش مشروط در غیر این صورت

ساختار if then else برای انتخاب یک گزینه کد در نظر گرفته شده است. اگر شرط خاصی درست باشد، کدی اجرا می شود و در غیر این صورت کد دیگری اجرا می شود. مثال زیر وجود یک فایل را بررسی می کند که پس از آن در صورت تایید فرض وجود فایل، پیام مربوطه نمایش داده می شود. اگر [ -f isit.txt ] #!/bin/bash باشد، فایل isit.txt وجود دارد را اکو کنید! در غیر این صورت فایل echo isit.txt یافت نشد! فی

در صورتی که پس انداز کنیم این کداسکریپت در فایلی به نام "choice"، می تواند به همین ترتیب اجرا شود. $ ./choice فایل isit.txt یافت نشد! $ لمس isit.txt $ ./انتخاب فایل isit.txt وجود دارد! $

پرش شرطی if then elif

می توانید پست کنید اپراتور جدیدپرش شرطی اگر داخل یک بلوک else با استفاده از عملگر elif باشد. در زیر یک مثال ساده از چنین ورودی آورده شده است. #!/bin/bash count=42 اگر [ $count -eq 42 ] سپس "42 یک مقدار معتبر است." elif [ $count -gt 42 ] سپس "Too many" را تکرار کنید. other echo "کافی نیست." فی

برای حلقه

مثال زیر نحو حلقه for کلاسیک را در پوسته bash نشان می دهد. برای من در 1 2 4 echo $i انجام شده است

مثالی از استفاده از حلقه for همراه با یک فراخوانی پوسته داخلی. #!/bin/ksh برای شمارنده در `seq 1 20` شمارش اکو از 1 تا 20، مقدار فعلی $counter sleep 1 انجام شد

یک اسکریپت کاملاً مشابه آنچه در بالا ارائه شده است را می توان بدون استفاده از پوسته فرمان جاسازی شده با استفاده از اعلان پوسته bash برای طیف وسیعی از مقادیر (از مقدار.. تا مقدار) ایجاد کرد. #!/bin/bash برای شمارنده در (1..20) شمارش اکو از 1 تا 20، مقدار فعلی $counter sleep 1 انجام شد

این حلقه for از مکانیزمی برای جستجوی فایل ها بر اساس الگو استفاده می کند (که به عنوان بخشی از مکانیزم گسترش فرمان پیاده سازی شده است). اگر دستورالعمل های فوق مستقیماً در خط فرمان، عملکرد مشابهی خواهد داشت. kahlan@solexp11$ ls count.ksh go.ksh kahlan@solexp11$ برای فایل در *.ksh ; انجام cp $file $file.backup ; انجام شد kahlan@solexp11$ ls count.ksh count.ksh.backup go.ksh go.ksh.backup

حلقه while

در زیر یک مثال ساده از استفاده از حلقه while آورده شده است. i=100; در حالی که [ $i -ge 0 ] ; انجام echo شمارش معکوس از 100 تا 0، مقدار فعلی $i. اجازه دهید من--؛ انجام شده

حلقه‌های بی‌نهایت را می‌توان با استفاده از اعلان‌های while true یا while پیاده‌سازی کرد، که در آن نماد: معادل عملیات گمشده در پوسته و bash Korn است. #!/bin/ksh # حلقه بی پایان در حالی که: echo hello sleep 1 انجام شد

تا حلقه

در زیر یک مثال ساده از استفاده از یک حلقه تا وجود دارد. اجازه دهید i=100; تا [ $i -le 0 ] ; انجام echo شمارش معکوس از 100 تا 1، مقدار فعلی $i. اجازه دهید من--؛ انجام شده

تمرین: تست ها و حلقه ها در اسکریپت ها

3. یک اسکریپت بسازید که از حلقه while برای شمارش از 3 تا 7 استفاده کند.

4. یک اسکریپت بسازید که از یک حلقه تا برای شمارش معکوس از 8 تا 4 استفاده کند.

5. یک اسکریپت ایجاد کنید که فایل‌های با پسوند txt را در فهرست فعلی شمارش کند.

6. اگر فایلی با پسوند txt در دایرکتوری فعلی وجود ندارد، از عبارت if در اسکریپت ایجاد شده استفاده کنید تا به درستی کار کند.

روش صحیح برای تکمیل یک کار عملی: بررسی ها و حلقه ها در اسکریپت ها

1. یک اسکریپت بسازید که از یک حلقه for برای شمارش از 3 تا 7 استفاده کند.

#!/bin/bash برای i در 3 4 5 6 7 do echo شمارش از 3 تا 7، مقدار فعلی $i انجام شد

2. یک اسکریپت بسازید که از یک حلقه for برای شمارش از 1 تا 17000 استفاده کند.

پوسته bash از حلقه‌ها پشتیبانی می‌کند، که به شما امکان می‌دهد روی دنباله‌ای از مقادیر را تکرار کنید. همین است ساختار اساسیچنین چرخه هایی:

برای var در لیست دستور do انجام شد
در هر تکرار حلقه، متغیر var به مقدار بعدی از نوشته می شود فهرست. بنابراین اولین پاس حلقه از اولین مقدار از لیست استفاده می کند. در دوم - دوم و غیره - تا زمانی که حلقه به آخرین عنصر برسد.

تکرار بر روی مقادیر ساده

شاید ساده‌ترین مثال حلقه for در اسکریپت‌های bash تکرار بر روی فهرستی از مقادیر ساده باشد:

#!/bin/bash برای var در اول دوم سوم چهارم پنجم do echo مورد $var انجام شد
نتایج این اسکریپت در زیر نشان داده شده است. شما به وضوح می بینید که متغیر $var شامل عناصری از لیست به صورت متوالی است. این اتفاق می افتد تا زمانی که چرخه به آخرین آنها برسد.


ساده برای حلقه

لطفا توجه داشته باشید که متغیر $var هنگام خروج از حلقه مقدار خود را حفظ می کند، محتویات آن قابل تغییر است و به طور کلی می توانید مانند هر متغیر دیگری با آن کار کنید.

تکرار بر روی مقادیر پیچیده

فهرستی که برای مقداردهی اولیه حلقه for استفاده می‌شود، نه تنها می‌تواند شامل رشته‌های ساده متشکل از یک کلمه، بلکه کل عباراتی باشد که حاوی چندین کلمه و علائم نگارشی هستند. به عنوان مثال، ممکن است به شکل زیر باشد:

#!/bin/bash برای var در اولین "دومین" "سوم" "I’ll do it" echo "This is: $var" انجام شد
این چیزی است که پس از اینکه این حلقه از لیست عبور می کند اتفاق می افتد. همانطور که می بینید، نتیجه کاملاً قابل انتظار است.


تکرار بر روی مقادیر پیچیده
TNW-CUS-FMP - کد تبلیغاتی برای 10٪ تخفیف در خدمات ما، برای فعال سازی ظرف 7 روز در دسترس است.

راه اندازی یک حلقه با لیستی که از نتایج فرمان بدست می آید

راه دیگر برای مقداردهی اولیه یک حلقه for این است که به آن لیستی ارسال کنید که نتیجه یک دستور است. در اینجا از جایگزینی دستور برای اجرای آنها و به دست آوردن نتایج کار آنها استفاده می شود.

#!/bin/bash file="myfile" برای var در $(cat $file) echo "$var" انجام شد
این مثال از دستور cat استفاده می کند که محتویات یک فایل را می خواند. لیست حاصل از مقادیر به حلقه منتقل می شود و روی صفحه نمایش داده می شود. لطفاً توجه داشته باشید که فایلی که ما به آن دسترسی داریم حاوی لیستی از کلمات است که با خطوط جدید جدا شده اند؛ هیچ فاصله ای استفاده نشده است.


حلقه ای که در محتویات یک فایل حلقه می زند

در اینجا باید در نظر بگیریم که چنین رویکردی، اگر پردازش خط به خط داده ها مورد انتظار باشد، برای فایلی با ساختار پیچیده تر، که خطوط آن ممکن است حاوی چندین کلمه باشد که با فاصله از هم جدا شده اند، کارساز نخواهد بود. حلقه تک تک کلمات را پردازش می کند نه خطوط.

اگر این چیزی نباشد که اصلاً نیاز دارید چه؟

جداکننده های میدان

دلیل ویژگی فوق خاص بودن آن است متغیر محیطیکه IFS (Internal Field Separator) نامیده می شود و به شما امکان می دهد جداکننده های فیلد را مشخص کنید. به طور پیش فرض، پوسته bash کاراکترهای زیر را به عنوان جداکننده فیلد در نظر می گیرد:
  • فضا
  • کاراکتر برگه
  • کاراکتر فید خط
اگر bash با هر یک از این کاراکترها در داده ها روبرو شود، فرض می کند که قبل از آن مقدار مستقل بعدی در لیست قرار دارد.

برای حل این مشکل، می توانید به طور موقت متغیر محیطی IFS را تغییر دهید. در اینجا نحوه انجام آن در یک اسکریپت bash آمده است، با این فرض که فقط به یک خط جدید به عنوان جداکننده فیلد نیاز دارید:

IFS=$"\n"
هنگامی که این دستور را به اسکریپت bash خود اضافه می کنید، همانطور که انتظار می رود کار می کند، فضاها و تب ها را نادیده می گیرد و فقط کاراکترهای خط جدید را به عنوان جداکننده فیلد در نظر می گیرد.

#!/bin/bash file="/etc/passwd" IFS=$"\n" برای var در $(cat $file) echo "$var" انجام شد
اگر این اسکریپت اجرا شود، دقیقا همان چیزی را که از آن خواسته شده است، خروجی می دهد و در هر تکرار حلقه، به خط بعدی نوشته شده در فایل دسترسی پیدا می کند.


پیمایش خط به خط یک فایل در حلقه for

جداکننده ها نیز می توانند شخصیت های دیگری باشند. به عنوان مثال، در بالا محتویات فایل /etc/passwd را نمایش دادیم. داده های کاربر در خطوط با دو نقطه از هم جدا می شوند. اگر نیاز به پردازش چنین رشته‌هایی در یک حلقه دارید، IFS را می‌توان به شکل زیر پیکربندی کرد:

عبور از فایل های موجود در یک دایرکتوری

یکی از رایج ترین موارد استفاده از حلقه های for در اسکریپت های bash، عبور از فایل های واقع در یک فهرست و پردازش آن فایل ها است.

به عنوان مثال، در اینجا نحوه فهرست کردن فایل ها و پوشه ها آمده است:

#!/bin/bash برای فایل در /home/likegeeks/* اگر [ -d "$file" ] انجام دهید، سپس "$file یک دایرکتوری است" elif [ -f "$file" ] و سپس echo "$file یک فهرست است" فایل" فی انجام شد
اگر مطالب قبلی در این سری مقالات را فهمیده اید، باید ساختار if-then construct و همچنین نحوه تشخیص یک فایل از یک پوشه را بدانید. اگر درک کد بالا برایتان دشوار است، این مطلب را دوباره بخوانید.

این همان چیزی است که اسکریپت خروجی خواهد داد.


نمایش محتویات یک پوشه

توجه کنید که چگونه حلقه را مقداردهی اولیه می کنیم، یعنی عام"*" در انتهای آدرس پوشه. این نماد را می توان به عنوان یک علامت عام در نظر گرفت به معنای: "همه فایل ها با هر نام". به شما امکان سازماندهی می دهد تعویض خودکارنام فایل هایی که با الگو مطابقت دارند.

هنگام آزمایش یک شرط در یک دستور if، نام متغیر را در گیومه قرار می دهیم. این کار به این دلیل انجام می شود که نام فایل یا پوشه ممکن است حاوی فاصله باشد.

سبک C برای حلقه ها

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

برای (i = 0; i< 10; i++) { printf("number is %d\n", i); }
در اسکریپت‌های bash می‌توانید از حلقه‌ها استفاده کنید، که شرح آن‌ها بسیار شبیه به حلقه‌های سبک C است، اگرچه تفاوت‌هایی نیز وجود دارد. نمودار چرخه با این رویکرد به شکل زیر است:

برای ((مقدار اولیه متغیر، شرط برای پایان دادن به حلقه، تغییر متغیر))
در bash می توان اینگونه نوشت:

برای ((a = 1; a< 10; a++))
در اینجا یک مثال کار آمده است:

#!/bin/bash برای ((i=1; i<= 10; i++)) do echo "number is $i" done
این کد لیستی از اعداد از 1 تا 10 را خروجی می دهد.

حلقه زدن به سبک C

حلقه while

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

در اینجا نموداری از سازماندهی حلقه های while آورده شده است
دستور while check condition
انجام دادن
تیم های دیگر
انجام شده

بیایید نگاهی به یک نمونه اسکریپت با حلقه ای مانند این بیندازیم:

#!/bin/bash var1=5 در حالی که [ $var1 -gt 0 ] echo $var1 var1=$[ $var1 - 1 ] انجام شد
در ورودی حلقه بررسی می شود که آیا متغیر $var1 بزرگتر از صفر است یا خیر. در این صورت بدنه حلقه اجرا می شود که در آن یک عدد از مقدار متغیر کم می شود. این در هر تکرار اتفاق می افتد و قبل از تغییر مقدار متغیر را در کنسول چاپ می کنیم. به محض اینکه $var1 به مقدار 0 رسید، حلقه متوقف می شود.

نتیجه حلقه while

اگر متغیر $var1 را تغییر ندهید، این باعث می شود که اسکریپت در یک حلقه بی نهایت قرار گیرد.

حلقه های تو در تو

می توانید از هر دستوری در بدنه حلقه استفاده کنید، از جمله راه اندازی حلقه های دیگر. چنین ساختارهایی حلقه های تودرتو نامیده می شوند:

#!/bin/bash برای ((a = 1; a<= 3; a++)) do echo "Start $a:" for ((b = 1; b <= 3; b++)) do echo " Inner loop: $b" done done
در زیر آنچه را که این اسکریپت خروجی می دهد آورده شده است. همانطور که می بینید، ابتدا اولین تکرار حلقه بیرونی اجرا می شود، سپس سه تکرار حلقه داخلی، پس از اتمام آن دوباره حلقه بیرونی و سپس دوباره درونی وارد بازی می شود.

حلقه های تو در تو

پردازش محتویات فایل

اغلب از حلقه های تو در تو برای پردازش فایل ها استفاده می شود. بنابراین، حلقه بیرونی روی خطوط فایل تکرار می شود، و حلقه داخلی در حال حاضر با هر خط کار می کند. برای مثال، پردازش فایل /etc/passwd چگونه است:

#!/bin/bash IFS=$"\n" برای ورود به $(cat /etc/passwd) echo "Values ​​in $entry –" IFS=: برای مقدار در $entry echo "$value" انجام شد انجام شده
دو حلقه در این اسکریپت وجود دارد. اولین مورد خطوط را با استفاده از کاراکتر خط جدید به عنوان جداکننده طی می کند. داخلی مشغول تجزیه رشته هایی است که فیلدهای آنها با دو نقطه از هم جدا شده اند.

پردازش داده های فایل

این رویکرد را می توان در هنگام پردازش فایل های CSV یا هر فایل مشابه، با نوشتن کاراکتر جداکننده در متغیر محیطی IFS در صورت نیاز استفاده کرد.

مدیریت چرخه

شاید پس از ورود به حلقه، زمانی که متغیر حلقه به مقدار مشخصی رسید که با شرایط اولیه مشخص شده برای پایان دادن به حلقه مطابقت ندارد، باید آن را متوقف کنید. آیا در چنین شرایطی باید منتظر کامل شدن عادی چرخه بود؟ البته نه، و در چنین مواردی دو دستور زیر مفید خواهند بود:
  • زنگ تفريح
  • ادامه هید

دستور شکستن

این دستور به شما اجازه می دهد تا اجرای یک حلقه را قطع کنید. می توان از آن برای هر دو حلقه for و while استفاده کرد:

#!/bin/bash برای var1 در 1 2 3 4 5 6 7 8 9 10 انجام دهید اگر [ $var1 -eq 5 ] سپس echo fi "Number: $var1" انجام شد
چنین حلقه ای در شرایط عادی کل لیست مقادیر موجود در لیست را طی می کند. اما در مورد ما، زمانی که متغیر $var1 برابر با 5 باشد، اجرای آن قطع خواهد شد.

خروج زود هنگام از یک حلقه for

در اینجا همان چیزی است، اما برای حلقه while:

#!/bin/bash var1=1 در حالی که [ $var1 -lt 10 ] اگر [ $var1 -eq 5 ] انجام دهید سپس echo fi "تکرار: $var1" var1=$(($var1 + 1)) را انجام دهید
دستور break که وقتی $var1 به عدد 5 رسید اجرا می شود، حلقه را می شکند. کنسول همان چیزی را که در مثال قبلی نشان داد نمایش می دهد.

ادامه فرمان

هنگامی که این دستور در بدنه حلقه مواجه می شود، تکرار فعلی زودتر به پایان می رسد و دستور بعدی بدون خروج از حلقه شروع می شود. بیایید به دستور continue در یک حلقه for نگاه کنیم:

#!/bin/bash برای ((var1 = 1; var1< 15; var1++)) do if [ $var1 -gt 5 ] && [ $var1 -lt 10 ] then continue fi echo "Iteration number: $var1" done
هنگامی که شرط داخل حلقه برآورده شد، یعنی زمانی که $var1 بزرگتر از 5 و کمتر از 10 باشد، پوسته دستور continue را اجرا می کند. این منجر به حذف دستورات باقی مانده در بدنه حلقه و رفتن به تکرار بعدی می شود.

دستور continue در یک حلقه for

پردازش خروجی در حال اجرا در یک حلقه

خروجی داده از یک حلقه را می توان با تغییر مسیر خروجی یا ارسال آن به خط لوله پردازش کرد. این کار با افزودن دستورات پردازش خروجی پس از دستور done انجام می شود.

به عنوان مثال، به‌جای نشان دادن آنچه در یک حلقه خروجی روی صفحه نمایش داده می‌شود، می‌توانید همه آن‌ها را در یک فایل بنویسید یا آن را در جای دیگری ارسال کنید:

#!/bin/bash برای ((a = 1; a< 10; a++)) do echo "Number is $a" done >myfile.txt اکو "تمام شد."
پوسته فایل myfile.txt را ایجاد می کند و خروجی دستور for را به آن فایل هدایت می کند. بیایید فایل را باز کنیم و مطمئن شویم که دقیقاً همان چیزی است که ما انتظار داریم.

تغییر مسیر خروجی حلقه به فایل

مثال: فایل های اجرایی را جستجو کنید

بیایید از آنچه قبلاً پوشش داده ایم استفاده کنیم و چیز مفیدی بنویسیم. به عنوان مثال، اگر شما نیاز به یافتن فایل های اجرایی موجود در سیستم دارید، می توانید تمام پوشه های ضبط شده در متغیر محیطی PATH را اسکن کنید. ما در حال حاضر کل زرادخانه ابزارهایی را که برای این کار نیاز داریم در اختیار داریم، فقط باید همه آنها را کنار هم بگذاریم:

#!/bin/bash.
این اسکریپت، کوچک و ساده، به ما این امکان را می دهد که لیستی از فایل های اجرایی ذخیره شده در پوشه ها را از PATH دریافت کنیم.

جستجوی فایل های اجرایی در پوشه ها از متغیر PATH

نتایج

امروز در مورد حلقه‌های for و while در اسکریپت‌های bash، نحوه اجرای آنها و نحوه مدیریت آنها صحبت کردیم. اکنون می‌دانید که چگونه رشته‌ها را با جداکننده‌های مختلف در حلقه‌ها پردازش کنید، می‌دانید که چگونه خروجی داده‌ها را در حلقه‌ها به فایل‌ها هدایت کنید، چگونه محتویات دایرکتوری‌ها را مشاهده و تجزیه و تحلیل کنید.

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

توضیح مختصری از تفاوت در انواع حلقه:

for - تا زمانی که اشیایی برای اجرا وجود داشته باشد یک عمل انجام می دهد (مثلاً خواندن یک جریان از stdin، یک فایل یا یک تابع).
while - عمل تا زمانی را انجام می دهد وضعیتدرست است؛
تا - تا زمانی که اجرا خواهد شد وضعیتدرست نخواهد شد، یعنی. در حال حاضر دروغ است.

برای حلقه

بیایید این نسخه از اسکریپت را با یک حلقه در نظر بگیریم:

$ cat loop.sh #!/bin/bash برای متغیر در `ls -1` اکو "$variable" انجام شد

نحو بسیار ساده است و به وضوح در مثال نشان داده شده است:

متغیر for (شروع حلقه) (متغیری را که بر روی آن اقدامات انجام خواهیم داد) در (ارسال یک جریان به حلقه) `ls -1` (فرمان اجرا شده و به متغیر متغیر $ ارسال می شود). Do و done "بدنه" حلقه هستند که در آن اقدامات اصلی روی داده های دریافتی انجام می شود و echo "$variable" عمل واقعی انجام شده توسط حلقه است.

حالا بیایید مثال را کمی تغییر دهیم و به جای اینکه دستور را به صراحت مشخص کنیم، از متغیر دوم استفاده می کنیم:

$ cat loop.sh #!/bin/bash ls=`ls -1` برای متغیر در $ls do echo "$variable" انجام شد

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

$ cat loop.sh #!/bin/bash lsl () ( ls -1 ) برای متغیر در `lsl` اکو "$variable" انجام شد

شرط اصلی حلقه for این است که تا زمانی که دستور ارسال شده به آن حاوی اشیایی برای عمل باشد، اجرا خواهد شد. بر اساس مثال بالا - تا زمانی که ls -1 فایل هایی برای نمایش داشته باشد - حلقه آنها را به یک متغیر منتقل می کند و "بدنه حلقه" را اجرا می کند. به محض پایان یافتن لیست فایل های دایرکتوری، حلقه اجرای خود را کامل می کند.

بیایید مثال را کمی پیچیده تر کنیم.

فهرست شامل لیستی از فایل ها است:

$ ls -1 file1 file2 file3 file4 file5 loop.sh nofile1 nofile2 nofile3 nofile4 nofile5

ما باید از بین آنها فقط آنهایی را انتخاب کنیم که کلمه "" را ندارند. نه«:

$ cat loop.sh #!/bin/bash lsl=`ls -1` برای متغیر در $lsl echo "$variable" | grep -v "نه" انجام شد $ ./loop.sh file1 file2 file3 file4 file5 loop.sh

همچنین می توانید از عبارات شرطی در یک حلقه استفاده کنید ( عبارات شرطی) […] برای بررسی شرایط و دستور break برای قطع کردن حلقه در صورت ایجاد شرط.

این مثال را در نظر بگیرید:

$ cat loop.sh #!/bin/bash lsl=`ls -1` برای متغیر در $lsl اگر [ $variable != "loop.sh" ] سپس "$variable" را بازتاب دهید | grep -v "نه" دیگر شکست فی انجام شد

حلقه تا زمانی که با فایل loop.sh مواجه شود ادامه خواهد داشت. به محض اینکه اجرای حلقه به این فایل رسید، حلقه با دستور break قطع می شود:

$ ./loop.sh file1 file2 file3 file4 file5

مثال دیگر استفاده از عملیات حسابی بلافاصله قبل از اجرای بدنه حلقه است:

$ cat loop.sh #!/bin/bash برای ((count=1; count<11; count++)) do echo "$count" done

در اینجا ما سه دستور کنترل را تنظیم می کنیم - count=1، یک شرط کنترلی - در حالی که count کمتر از 11 است، و یک دستور برای اجرا - count +1:

حلقه های WHILE و UNTIL

یک مثال ساده که به وضوح نحوه عملکرد حلقه while را نشان می دهد:

$ cat loop.sh #!/bin/bash count=0 در حالی که [ $count -lt 10 ] انجام ((count++)) echo $count انجام شد

متغیر $count را صفر می کنیم و سپس حلقه whi le را با این شرط اجرا می کنیم که "در حالی که $count کمتر از ده است، حلقه را اجرا کنید." در بدنه حلقه اجرا می کنیم افزایش پسوندبه متغیر $count 1+ کنید و نتیجه در stdout چاپ می‌شود.

نتیجه اجرا:

$ ./loop.sh 1 2 3 4 5 6 7 8 9 10

به محض اینکه مقدار متغیر $count 10 شد، حلقه متوقف شد.

یک مثال خوب از یک حلقه "بی نهایت" که نحوه عملکرد while را نشان می دهد:

$ cat loop.sh #!/bin/bash count=10 while [ 1 = 1 ] do ((count++)) echo $count done $ ./loop.sh ... 5378 5379 5380 5381 5382 5383 ^C

حلقه تا به طور مشابه کار می کند، اما در جهت مخالف:

$ cat loop.sh #!/bin/bash count=0 تا زمانی که [ $count -gt 10 ] انجام شود ((count++)) echo $count تمام شد

در اینجا ما یک شرط مشابه را تعیین می کنیم، اما به جای "در حالی که متغیر کمتر از 10 است"، "تا زمانی که متغیر بزرگتر از 10 شود" را مشخص می کنیم. نتیجه اجرا:

$ ./loop.sh 1 2 3 4 5 6 7 8 9 10 11

اگر مثال بالا از یک "حلقه بی پایان" با استفاده از تا اجرا شود، بر خلاف while:

$ cat loop.sh #!/bin/bash count=10 تا زمانی که [ 1 = 1 ] انجام دهد ((count++)) echo $count done $ ./loop.sh $

زیرا " وضعیت"در اصل" درست است، واقعی"- بدنه حلقه اجرا نخواهد شد.

درست مانند حلقه for، می توانید از توابع در while و while استفاده کنید. به عنوان مثال، یک حلقه از یک اسکریپت واقعی که وضعیت سرور را بررسی می کند تامکت(PID از سیستم گرفته شده است SLES، ممکن است در سیستم های دیگر متفاوت باشد)، یک نسخه کمی ساده شده:

$ cat loop.sh #!/bin/bash check_tomcat_status () (RUN=`ps aux | grep tomcat | grep -v grep | grep java | awk "(print $2)"` ) در حالی که check_tomcat_status را اگر [ -n "$ انجام دهید RUN" ] سپس printf "WARNING: Tomcat هنوز با PID $RUN در حال اجرا است." else printf "تامکت متوقف شد، ادامه داشت...nn" شکستن فی انجام شد

نتیجه اجرا:

$ ./loop.sh اخطار: تامکت همچنان با PID 14435 26548 در حال اجراست. اخطار: تامکت هنوز با PID 14435 در حال اجراست 26548. اخطار: تامکت هنوز با PID 14435 26548 در حال کار است. اخطار: Tomcat هنوز با PID 14435 در حال اجرا است. اخطار: Tomcat هنوز با PID 14435 در حال اجرا است. هشدار: Tomcat هنوز با PID 14435 در حال اجرا است. در حال اجرا با PID 14435 26548. اخطار: Tomcat همچنان با PID 14435 26548 در حال اجرا است. هشدار: Tomcat هنوز با PID 14435 26548 در حال اجرا است. هشدار: Tomcat همچنان با PID 14435 در حال اجرا است.

نسخه کامل:

Check_tomcat_status () ( RUN=`ps aux | grep tomcat | grep -v grep | grep java | awk "(print $2)"` ) while check_tomcat_status; انجام دهید اگر [ -n "$RUN" ] سپس printf "WARNING: Tomcat هنوز با PID $RUN در حال اجرا است. متوقفش کنید؟" پاسخ دهید "توقف Tomcat..." "در حال نصب..." && $CATALINA_HOME/bin/shutdown sh 2&>1 /dev/null || شکستن خواب 2 اگر [ -n "$RUN" ] سپس printf "تامکت هنوز در حال اجراست. بکش؟" پاسخ "کشتن تامکت..." "در حال نصب...n" && kill $RUN || break sleep 2 fi other printf "Tomcat متوقف شد، ادامه داشت...nn" break fi انجام شد

تابع پاسخ در مقاله توضیح داده شد، اما در اینجا از یک نسخه کمی بهبود یافته استفاده شده است:

پاسخ () (در حالی که پاسخ خوانده می‌شود؛ echo case $response را در |) printf "$1n" return 0 break ;; |) printf "2n$" بازگشت 1 شکست ;; *) printf "لطفا، Y(بله) یا N(خیر) را وارد کنید! " esac done)

در اینجا می‌توان هم از while و هم استفاده کرد - اما نه از حلقه for، زیرا for یک بار کار می‌کرد (PID را دریافت کرد و به پایان رسید).

حلقه ها هنگام نوشتن هر برنامه یا اسکریپتی بسیار راحت هستند، بلکه حتی ضروری هستند. آنها به ما این امکان را می دهند که یک بخش مشخص از کد را چند بار مشخص اجرا کنیم. به طور طبیعی، bash دارای چندین نوع حلقه است. ما چرخه ها را شرح خواهیم داد برای در، برای، در حالی که، تا. اگرچه for in و for نحوهای متفاوتی از یک عبارت در نظر گرفته می شوند، به نظر من آنها بیش از while از تا با یکدیگر تفاوت دارند.

حلقه با شمارنده برای in:

چرخه برای دراین یک حلقه با شمارنده است. بلوک کد واقع در بدنه حلقه به تعداد مقادیر موجود در لیست عملگر for in تکرار می شود و با هر تکرار متغیر شمارنده (در اینجا var نامیده می شود، البته البته می توانید آن را هر چه دوست دارید صدا کنید) دارای مقدار عنصر بعدی لیست است.
اگر کلمه کلیدی do در همان خط کلمه for قرار دارد، پس از لیست آرگومان ها (قبل از انجام) باید یک نقطه ویرگول قرار دهید.
هر یک از عناصر<список>ممکن است حاوی چندین آرگومان باشد. این هنگام پردازش گروهی از پارامترها مفید است. در این حالت، تجزیه هر یک از آرگومان ها را اجباری کنید<списке>، باید از دستور set استفاده کنید
می توانید از یک متغیر به عنوان لیست در حلقه for استفاده کنید.
که در<списке>حلقه for می تواند از نام فایل ها استفاده کند که به نوبه خود می تواند شامل کاراکترهای عام باشد. این می تواند هنگام کار با تعداد زیادی فایل بسیار مفید باشد.
اگر<список>در حلقه for مشخص نشده است، سپس متغیر $@ به عنوان آن استفاده می شود - لیستی از آرگومان های خط فرمان.
هنگام ایجاد لیستی از آرگومان ها، می توانید از جایگزینی دستور در حلقه for استفاده کنید.
خروجی حلقه را می توان از stdout به یک فایل یا جای دیگری هدایت کرد (با مشاهده تغییر مسیر I/O می توانید در مورد این موضوع بیشتر بدانید).

نحو:
برای var in<список>
انجام دادن
<выполняемые команды>
انجام شده

مثال:
برای نام ها در name1 name2 name3 name4
انجام دادن
echo $names
انجام شده

عملگر حلقه برایروش دیگری برای نوشتن دارد - بسیار شبیه به نحو عملگر for در زبان C. در این حالت، هنگام مقداردهی اولیه شمارنده ها، مقادیر اولیه متغیرها یا یک متغیر تنظیم می شود و پس از هر عبور از حلقه، شرط قرار می گیرد. بررسی می شود، اگر چک true را برگرداند، پاس بعدی حلقه شروع می شود. در بلوک<приращение счётчиков>مقدار شمارنده های متغیر ما لزوماً باید تغییر کند (نه لزوماً به سمت بالا) تا هنگام بررسی شرط دیر یا زود مقدار false را دریافت کنیم، در غیر این صورت حلقه هرگز تمام نمی شود. یک گزینه بسیار راحت و مهمتر از همه آشنا در صورتی که هر عملیاتی نیاز به تکرار چند بار مشخص داشته باشد.

با یک نحو مشابه:
برای ((<инициализация счётчиков>; <проверка условия>; <приращение счётчиков>))
انجام دادن
<выполняемые команды>
انجام شده

مثال:
برای ((var=1; var<= LIMIT ; var++))
انجام دادن
echo $var
انجام شده

حلقه while:

این یک ساختار نسبتاً ساده است که وضعیت پشت اپراتور را بررسی می کند در حالی کهو اگر این شرط درست باشد، بلوک دستورات واقع بین کلمات do و done را اجرا می کند و دوباره به بررسی شرط می پردازد. اگر چک غلط را برگرداند، چرخه به پایان می رسد و دستورات زیر شروع به اجرا می کنند: انجام شده. اطمینان از آن ضروری است<проверка условия>بستگی به کد در حال اجرا در حلقه دارد، در غیر این صورت، اگر نتیجه بررسی تغییر نکرد، یک حلقه بی نهایت دریافت خواهید کرد.
دستگاه ورودی استاندارد برای حلقه while را می توان با استفاده از دستور redirection به یک فایل هدایت کرد< в конце цикла.

نحو:
در حالی که<Проверка условия>
انجام دادن
<Блок команд, обязательно меняющий переменные влияющие на проверку условия>
انجام شده

مثال:
در حالی که [$var0 -eq 100]
انجام دادن
echo $var
var++
انجام شده

اپراتور در حالی کهممکن است شرایط متعددی داشته باشد. اما تنها آخرین آنها امکان ادامه چرخه را تعیین می کند. در این حالت، نحو عملگر حلقه با حالت معمول متفاوت خواهد بود.
نحو(یک بار دیگر تکرار می کنم که تنها شرط آخر بر اجرای حلقه تأثیر می گذارد) :
در حالی که
<условие1>
<условие2>

<условиеN>
انجام دادن
<выполняемые команды - тело цикла>
انجام شده

تا حلقه:

اپراتور تا زمانبسیار شبیه به while است، شرایط را نیز ارزیابی می کند، اما اگر نتیجه محاسبه نادرست باشد، بدنه حلقه را اجرا می کند. ممکن است غیرعادی به نظر برسد، اما تا زمانی که شرایط را قبل از اولین پاس حلقه ارزیابی می کند، مانند while، و نه بعد از آن. همانند حلقه‌های for/in، هنگام قرار دادن کلمه کلیدی do در همان خط اعلان حلقه، باید یک کاراکتر ";" را وارد کنید. قبل از انجام
مانند مورد قبلی، مهم است که به یاد داشته باشید که شرط باید به عملیات در بدنه حلقه بستگی داشته باشد، در غیر این صورت اسکریپت ما هرگز کامل نخواهد شد.

نحو:
تا زمان<Проверка условия>
انجام دادن
<Блок команд, обязательно меняющий переменные влияющие на проверку условия>
انجام شده

مثال:
تا [$var0 -gt 100] # شرط در ابتدای تکرار بررسی می شود.
انجام دادن
echo $var
var--
انجام شده

احتمالا فعلا همین کافی است. :)

  • بازگشت
  • رو به جلو

مقالات جدید:

  • کشف شبکه در ویندوز 7/8/2008/2012 روشن نمی شود
  • خطا: این برنامه راه اندازی نشد زیرا نتوانست پلاگین پلتفرم Qt "windows" را پیدا یا بارگیری کند.
  • پیکربندی راه اندازی مجدد خودکار فرآیندهای کارگر rphost.exe در سرور 1C 8.3
  • نحوه کاهش اندازه گزارش تراکنش (.ldf) در MS SQL 2008/20012

    MS SQL، مانند هر DBMS صنعتی مناسب، همراه با پایگاه داده، گزارش های تراکنش را نگه می دارد که به شما امکان می دهد وضعیت را به عقب برگردانید...

0 میران بالا-کوماران

من واقعاً سعی می‌کنم بفهمم چرا این حلقه while هرگز تمام نمی‌شود، وقتی حلقه شروع می‌شود، متغیر LOC من روی Testing تنظیم می‌شود/ که دایرکتوری که برای آزمایش این برنامه ایجاد کردم دارای طرح‌بندی زیر است:

من می خواهم زمانی که همه دایرکتوری ها تابع "count" را داشته باشند، حلقه به پایان برسد.
این چیزی است که من امتحان کردم.

من تابع count را بررسی کردم و حلقه بی نهایت ایجاد نمی کند

من سعی کردم الگوریتم را به صورت دستی اجرا کنم

PARSE=1 LOC=$LOC/ شمارش AVAILABLEDIR=$(ls $LOC -AFl | sed "1 d" | grep "/$" | awk "( print $9 )") در حالی که [$PARSE = "1" ] اگر [[ $(AVAILABLEDIR[@]) == "" ]]; سپس PARSE=0 fi DIRBASE=$LOC برای یک در $(AVAILABLEDIR[@]); انجام LOC="$(DIRBASE)$(a)" LOCLIST="$LOCLIST $LOC" برای یک در $(LOCLIST[@]); do TMPAVAILABLEDIR=$(ls $a -AFl | sed "1 d" | grep "/$" | awk "( print $9 )") PREPEND=$a if [[ $(TMPAVAILABLEDIR[@]) == "" ] ]؛ سپس fi را در $(TMPAVAILABLEDIR[@]) ادامه دهید. انجام TMPAVAILABLEDIR2="$TMPAVAILABLEDIR2 $(PREPEND[@])$(a)" انجام شد NEWAVAILABLEDIR="$NEWAVAILABLEDIR $TMPAVAILABLEDIR2" انجام شد AVAILABLEDIR=$NEWAVAILABLEDIR NEWAVAILABLEDIR="" LOC="" انجام شد

من واقعاً در حال مبارزه هستم و هر ورودی بسیار قابل قدردانی است، من در دو ساعت گذشته سعی کرده ام این را بفهمم.

حلقه بی نهایت bash

4 پاسخ

باید اسکریپت را با آرگومان x- اجرا کنید یا آن را در خط اول بنویسید:

#!/bin/bash -x

سپس هر کاری که انجام می دهد به شما می گوید.

در این مورد، ممکن است متوجه دو خطا شوید:

    شما هرگز TMPAVAILABLEDIR2 را دوباره بارگیری نمی کنید

    شما همچنین ls را روی فایل های معمولی انجام می دهید.

اگر واقعاً باید از بازگشت اجتناب کنید، این را کاملاً بدون بازگشت امتحان کنید:

#!/bin/bash count() ( echo counting "$1" ) todo=(Testing) while test $(#todo[@]) != 0 doit=("$(todo[@])") todo= () برای dir در "$(doit[@])" برای ورود در "$dir"/* # اگر dir خالی است، این ورودی به نام "*" do test -e "$entry" || ادامه # رد شدن از ورودی "*" یک عدد dir خالی تست "$entry" -d "$entry" || ادامه todo+=("$entry") انجام شد انجام شد

با این حال، لطفا به من بگویید چرا نمی توانید از بازگشت استفاده کنید؟ آیا این نوعی آلرژی است؟ نذر؟ آیا قوانین محلی علیه نرم افزارهای بازگشتی در محل زندگی شما وجود دارد؟

شما نوشته اید که می خواهید روی همه برش ها یک "شمار" انجام دهید. گزینه های جستجو را بررسی کنید:

$LOC -type d | را پیدا کنید هنگام خواندن dir; انجام cd $LOC cd $(dir) شمارش انجام شد

یا کوتاهتر (زمانی که شمارنده تابع شما دایرکتوری را به عنوان پارامتر 1 می گیرد)

$LOC -type d | را پیدا کنید تعداد xargs

اکنون می بینم که شما نمی خواهید از find یا ls -R (تابع بازگشتی) استفاده کنید. سپس باید تابع بازگشتی خود را مانند آن بسازید

تابع parseDir ( ls -d */ $1 | در حالی که dir خوانده می شود؛ parseDir $1/$dir انجام شده را بشمارید)

من نمی دانم که آیا این کار می کند یا خیر، اما یک سوال جالب است که نمی توانستم به آن فکر نکنم. موفق باشید

در حالی که درست است؛ برای کلمه در "$(echo *)" ; انجام دهید اگر [[ -d "$word" ]] ; سپس d[$((i++))]="$PWD"/"$word" elif [[ -f "$word" ]] ;سپس f[$((j++))]="$PWD"/"$ word" fi done [[ $k -gt $i ]] && cd .. cd "$d[$((k++))]" || شکست انجام شد