چرا حلقه for در دایرکتوری اجرا نمی شود؟ چرا حلقه for در دایرکتوری Loops در اسکریپت های bash اجرا نمی شود

صفحه اصلی / روشن نمی شود

توجه:مزایایی در پست پنهان است!

برای حلقه ها

پوسته 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 یک فهرست است" فایل" فی انجام شد

پوسته 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 else printf "Tomcat متوقف شد، ادامه دارد...nn" break fi انجام شد

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

پاسخ () (در حالی که پاسخ خوانده می شود؛ بازتاب حالت $response در |) printf "$1n" return 0 break ;;

5

|) printf "2n$" بازگشت 1 شکست ;;

*) printf "لطفا، Y(بله) یا N(خیر) را وارد کنید! " esac done)

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

1) اسکریپت شما به روشی خطرناک کدگذاری شده است. ابتدا، من فرض می‌کنم که از پوسته Bash استفاده می‌کنید، زیرا آن را با "/bash" و "/for" علامت‌گذاری کرده‌اید.در پاسخ خود من این راهنمای عالی Bash را نقل می کنم که احتمالاً بهترین منبع برای یادگیری Bash است.

به طور خاص، $(find$ DIRWORK -type d -name work) و $(find$ DIR -type f) تحت تقسیم کلمه قرار خواهند گرفت، بنابراین اگر find فایلی با فاصله در نام خود پیدا کند، یعنی "filename"، نتیجه تقسیم کلمه است. Bash 2 آرگومان را برای تکرار به دستور for ارسال می کند، یعنی یکی برای "file" و دیگری برای "name". در این مورد، می‌خواهید امیدوار باشید که "فایل: هیچ فایل یا دایرکتوری وجود ندارد" و "نام: هیچ فایل یا فهرستی وجود ندارد" به جای اینکه به طور بالقوه به آنها آسیب برسانید اگر واقعاً وجود داشته باشند.

2) طبق قرارداد، متغیرهای محیطی (PATH، EDITOR، SHELL، ...) و متغیرهای پوسته داخلی (BASH_VERSION، RANDOM، ...) کاملاً با حروف بزرگ نوشته می‌شوند. نام سایر متغیرها باید با حروف کوچک باشد. از آنجایی که نام متغیرها به حروف کوچک و بزرگ حساس هستند، این قرارداد از نادیده گرفتن تصادفی متغیرهای محیطی و داخلی جلوگیری می کند.

این نسخه ایمن تری از اسکریپت شما است که توصیه می کنم به جای آن از آن استفاده کنید:

My_home="/root/mydir" my_dir=" $my_home/var" dir_work="$ my_home/Local" در حالی که IFS= read -r -d "" f; # حدس می‌زنم که شما هم می‌خواهید stderr را نادیده بگیرید؛ # اینجا همان جایی است که 2>&1 از آنجا آمده است. اگر lsof -n "$f" | grep "" > /dev/null 2> سپس "hey" را تکرار کنید. من "الان امن ترم!"< <(find "$ dir_work" -type f -print0) while IFS= read -r -d "" f; do echo "2" done < <(find "$dir_work" -type d -name "work" -print0)

فی انجام شد

همانطور که می بینید، متغیر IFS روی خالی تنظیم شده است، بنابراین از برش دادن فضای جلو و عقب از خط جلوگیری می کند. دستور read از خط خالی (-d ") به عنوان جداکننده برای خواندن استفاده می کند تا زمانی که به a\0 برسد باید بر اساس آن m باشد، بنابراین از گزینه -print0 برای جداسازی داده های خود با \0 به جای خط جدید استفاده می کند. ، به طور شگفت انگیز و مخرب، می تواند بخشی از نام فایل باشد. تقسیم چنین فایل \n به دو قسمت باعث شکسته شدن کد ما می شود.

پاسخ قبلی که بیان کرد که پیدا کردن... | هنگام خواندن نام; انجام...؛ done باید برای خواندن استفاده شود. خروجی Find نیز می تواند بد باشد. حلقه while در یک زیر پوسته جدید اجرا می شود که کپی خودش از متغیرها از والد آن کپی شده است. سپس این کپی برای هر چیزی که دوست دارید استفاده می شود. وقتی حلقه while تمام شد، کپی زیر پوسته حذف می‌شود و متغیرهای اصلی والدین تغییر نمی‌کنند.

0

"هرگز از جایگزینی فرمان، از هر نوعی، بدون علامت نقل قول استفاده نکنید." این فقط یک نکته ساده است، اما زمانی که یک متغیر را تنظیم می‌کنید، می‌توانید از جایگزینی دستور بدون نقل قول استفاده کنید: "something = $(نام پایه" نام فایل با فاصله ")". - اسمیت جان 22 آوریل 13 2013-04-22 21:43:10

2

برای i در $(یافتن$ DIRWORK -type d -name work); echo "2" انجام شد

اولین کسی خواهد بود که این خط را اجرا می کند

کار $DIRWORK -type d -name را پیدا کنید

صبر کنید تا اجرای Find به پایان برسد و سپس یک روز مرخصی بگیرید و دوباره آن را در حلقه for قرار دهید

برای i در خروجی find; echo "2" انجام شد

تنها در این صورت حلقه for شروع به اجرا می کند.

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

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

$ time پیدا کردن $DIRWORK -type d -name work

و ببینید چقدر طول می کشد

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

Find$ DIRWORK -type d -name work | هنگام خواندن نام; echo "2" انجام شد

پاداش: یک حلقه while به موازات find اجرا می کند. این بدان معناست که حلقه while به محض اینکه find یک خط را چاپ کند، یک تکرار را تکمیل می کند. برای اجرای کامل نیازی به صبر کردن برای Find نیست.

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

برای حلقه

چرخه برای V ضربه شدیددو نوع دارد بیایید ابتدا به نسخه کلاسیک نگاه کنیم برای. نمای کلی به شرح زیر است:

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

در اینجا یک مثال عملی آورده شده است:

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

نتیجه مانند مثال اول خواهد بود.

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

نتیجه:

به نوع دوم برگردیم برای. اغلب در اسکریپت ها می توانید نوع به اصطلاح C-like را پیدا کنید برای، که برای حلقه های مبتنی بر عدد استفاده می شود. بیایید به یک مثال نگاه کنیم:

حلقه تا زمانی اجرا می شود که شرط مورد آزمایش در عبارت درست باشد. به محض اینکه عبارت false برگرداند، حلقه اجرا را متوقف می کند.

مثال عملی:

#!/bin/bash
i=1
در حالی که [$i -lt 7 ]
انجام دهید
پژواک $i
اجازه دهید i=i+1
انجام شد

در مثال ما، آن متغیر را بررسی می کنیم منکوچکتر از (-lt) عدد 7 است و اگر چنین است، مقدار متغیر روی صفحه نمایش داده می شود. بیان اجازه دهید i=i+1، متغیر را یک بار افزایش می دهد، دوباره بررسی می کند و غیره. let به مفسر می گوید که آرگومان ها باید به عنوان مقادیر عددی شناسایی شوند. این خط می تواند به صورت نوشته شود اجازه دهید من ++(نوعی مانند c). هنگامی که یک عدد بیش از یک افزایش می یابد، می توان آن را به صورت زیر نوشت: اجازه دهید i+=2- در این مورد منبا افزایش 2 افزایش می یابد. گزینه دیگر برای افزایش یک متغیر استفاده از ماشین حساب داخلی است (فقط با اعداد صحیح کار می کند). از طریق دو براکت می توان به ماشین حساب دسترسی داشت: i=$(($i+1))یا از طریق مربع ها: i=$[$i+1]همچنین می توانید از ماشین حساب در خط فرمان استفاده کنید:

شما باید مراقب حلقه ها باشید تا در نهایت به یک حلقه بی پایان نرسید. در ضمن برای رفع اشکال ضربه شدیداسکریپت هایی که می توانید خط اول را به آنها تغییر دهید #!/bin/bash -xیا اسکریپت را با دستور اجرا کنید bash -x:

igor@ubuntu:~/linux$ bash -x ./testfor.sh
+ i=1
+ '[' 1 -gt 5 ']'
+ echo i=1
i=1
+ اجازه دهید i=i+1
+ '[' 2 -gt 5 ']'
+ echo i=2
i=2
+ اجازه دهید i=i+1
+ '[' 3 -gt 5 ']'
+ echo i=3
i=3
+ اجازه دهید i=i+1
+ '[' 4 -gt 5 ']'
+ echo i=4
i=4
+ اجازه دهید i=i+1
+ '[' 5 -gt 5 ']'
+ echo i=5
i=5
+ اجازه دهید i=i+1
+ '[' 6 -gt 5 ']'

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

توابع در bash

توابع در استفاده می شود ضربه شدیدبسیار گسترده توابع به دو صورت توصیف می شوند: با یک کلمه کلیدی تابع، و بدون آن.

راه اول:

تابع function_name
{
بدن عملکرد
}

راه دوم:

function_name()
{
بدن عملکرد
}

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

#!/bin/bash
پرایمر عملکردی
{
اگر [$# -ne 0 ]
سپس
محلی a=1
echo "تعداد پارامترهای ارسال شده - $#"
برای من در $@
انجام دهید
echo "$a-امین پارامتر $i است"
اجازه دهید ++
انجام شد
بازگشت 0
دیگر
echo "پارامترها تصویب نشدند"
بازگشت 1
فی
}
echo "فراخوانی یک تابع با پارامترها:"
آغازگر a b c
اکو $؟
echo "فراخوانی یک تابع بدون پارامتر:"
آغازگر
اکو $؟

در این مثال، تابعی به نام آغازگر. فراخوانی یک تابع با پارامترها: آغازگر a b cو بدون پارامتر: آغازگر. در بدنه تابع، تمام ساختارها باید برای شما آشنا باشند، به استثنای $# , $iو $@ .$# — تعداد پارامترهای ارسال شده به تابع را برمی گرداند. در مثال ما این عدد خواهد بود 3 .$@ تمام پارامترها را در یک خط برمی گرداند. در مثال آن خواهد بود a b c. و از طریق $1 , $2 , $3 و غیره شما می توانید به هر پارامتر به صورت جداگانه دسترسی داشته باشید. $? - حاوی کد اجرای آخرین دستور است. در مثال ما، کد اجرای تابع.

این تابع همچنین می تواند یک مقدار عددی را از طریق یک کلمه کلیدی برگرداند بازگشت. معمولاً اگر عملکرد بدون خطا اجرا شود 0 یا اگر مشکلی پیش بیاید مقدار غیر صفر را برمی‌گردانند. در مثال، اگر تابعی با پارامتر فراخوانی شود، مقدار 0 برگردانده می شود و اگر تابع بدون پارامتر فراخوانی شده باشد، کد 1 برگردانده می شود.

همه چیز در مورد ارسال پارامترها به یک تابع دقیقاً برای یک اسکریپت کار می کند. شما همچنین می توانید پارامترها را به اسکریپت ارسال کنید و آنها را به همان روش با استفاده از دستکاری کنید $#، $@، $N. از همان دسته گزینه است - $0 - که نام دستوری را که اسکریپت را راه اندازی کرده است برمی گرداند. اگر اسکریپت با دستور اجرا می شد ./script.sh، سپس اکو $0 مقدار را برمی گرداند ./script.sh، و اگر به دستور باشد /home/igor/linux/script.sh، سپس مقدار برگردانده می شود /home/igor/linux/script.sh.

© 2024 ermake.ru -- درباره تعمیر رایانه شخصی - پورتال اطلاعاتی