Professional Documents
Culture Documents
Linux Farsi
Linux Farsi
" #
&'( $ %
) * + , -!
1/322 محیط برنامه سازی لینوکس
شما يك مبتدی هستید ،مسائل تصادفي زيادی وجود دارد که شما ميتوانید با انجام آنها به خودتان يا ديگر کاربران آسیب برسانید.
بنابراين ،چگونگي عملکرد آن مسائل را با تلش و کوشش بر روی آنها فرا گیريد .اين فصل ،فصل بسیار طولني است و بهترين راه
برای مطالعه آن اين است که هر دفعه چند صفحه را مطالعه کنید و مادامي که به پیش ميرويد ،مطالب را مورد آزمايش و بررسي قرار
دهید.
برخي از مقدمات در مورد پايانهها و تايپ به منظور اجتناب از تشريح هر مورد پیرامون استفاده از کامپیوترها ،ما بايد فرض کنیم که
شما آشنايي مخصتری با پايانههای کامپیوتر و چگونگي استفاده از آنها داريد .در صورتي که هر کدام از جملت زير مبهم و پیچیده
باشد ،ما بايد به منظور درك آن از کارشناس سؤال کنیم .سیستم يونیکس ،سیستم دو طرفه کامل است ،يعني علئم و حروفي که شما از
طريق صفحه کلید ،تايپ ميکنید به سیستم انتقال پیدا ميکند ،به نحوی که سیستم آنها را به پايانهها به منظور چاپ بر روی صفحه
نمايش ،بر ميگرداند .به طور طبیعي ،اين فرايند انعکاس ،علئم و حروف را به طور مستقیم در صفحه نمايش ،کپي ميکند ،بنابراين
شما ميتوانید آنچه را که شما در حال تايپ آن هستید را ببنید اما ،بعضي اوقات همچون زماني که شما در حال تايپ يك کلمه رمز
هستید ،فرايند انعکاس قطع ميشود ،بنابراين علئم و حروف بر روی صفحه نمايش ،نمايان نميشود .اغلب علئم و حروف صفحه
کلید ،بدون هیچ مفهوم خاصي از جمله علئم چاپي معمولي و رايج به شمار ميآيند ،اما تعداد کمي از آنها به کامپیوتر چگونگي تفسیر
تايپ شما را اعلم ميکند .به مراتب ،مهمترين اين موارد ،کلید Returnاست .کلید Returnبه معنای پايان خط ورودی است ،سیستم
اين معنا را با حرکت مکان نما پايانه به ابتدای خط بعدی در صفحه نمايش ،منعکس ميسازد .کلید Returnبايد قبل از اينکه سیستم
بخواهد علئمي که شما تايپ کردهايد را تفسیر و تعبیر کند ،فشار داده شود .کلید Returnنمونهای از علئم کنترلي است ،يعني يك
علمت غیر قابل رؤيتي که برخي از جنبههای ورودی ـ خروجي را برروی پايانهها ،کنترل ميکند .بر روی هر کدام از پايانههای مستدل
(منطقي) Return ،دارای يك کلید مخصوص به خود است .اما اغلب علئم کنترلي چنین نیستند .در عوض آنها بايد به وسیله پايین نگه
داشتن کلید Controlتايپ شوند ،بعضي اوقات تحت عنوان Ctlيا CNTLيا CL RLاز آنها ياد ميشود .بعد از آن ،کلید ديگری را
فشار دهید که معمول ً آن کلید شامل يك حرف است .برای مثال »Return « :ممکن است به وسیله فشار دادن کلید Returnيا
شرايط مشابه به آن يا پايین نگه داشتن کلید Contrlو تايپ’ ‘mتايپ شود .بنابراين Returnممکن است شامل CTl-dباشد که بیان
کنندة برنامهايي است که ديگر شامل ورودی نیست CTl-g ،که شامل صدای زنگ موجود بر روی پايانهها است CTl-h ،غالبا ً ،کلید
backspaceنامیده ميشود که ميتواند به منظور تصحیح خطاهای کپي به کار برده شود و CTL-Iکه غالباًُ کلید Tabنامیده ميشود
که مکاننما را به نقطه Tabبعدی به جلو ميبرند ،که اين فرايند بیشتر شبیه به ماشین تحرير تنظیمي ،عمل ميکند .نقطه Tabدر
سیستمهای يونیکس به اندازه هشت ( )8کاراکتر از يکديگر فاصله دارند .هر دو علمت backspaceو Tabدر اغلب پايانهها دارای
کلیدهای مخصوص به خود هستند.دو کلید ديگر وجود دارد که دارای معنای مشابه به يکديگر ميباشد .کلید deleteکه بعضي اوقات
rub-outيا برخي ديگر از علئم اختصاری و breakنامیده میشوند ،و بعضي اوقات interruptنامیده ميشوند .در اغلب سیستمهای
يونیکس ،کلید deleteبدون لحظهای درنگ برای پايان دادن برنامه ،آن را بلفاصله متوقف ميسازد .در برخي از سیسمتهاCTL-c ،
اين کار را انجام ميدهد .و در برخي از سیستمها ،با توجه به اين نکته که پايانهها چگونه متصل ميشوند ،کلید breakبرای deleteيا
CTL-cبه عنوان کلیدی هم معنا و دارای همان فعالیت ،معرفي ميشود.
3/322 محیط برنامه سازی لینوکس
آنچه را که، از طريق مثالهای موجود در اين کتاب، بحث را آغاز کنیم، اجازه دهید که با گفتگويي پیرامون شما و سیستم يونیکس تان
پاسخهای کامپیوتر به صورت علئمي به سك ماشین تحرير است و، شما تايپ کردهايد در حروفهايي به صورت موب چاپ شده است
توضیحات و تعريف به صورت موب است
: سیستمتان بايد اين موارد را اعلم کند. شماره ای بگیريد يا دکمهای را در صورت لزوم روشن کنید: ارتباطي را ايجاد کنید
مابقي اين بخش. همانگونه که بسیاری از افراد چنین ميکند،بعضي اوقات تمام مواردی که در اينجا بیان شد شامل يك مرحله است
. بحث ميکند،در مورد قسمت بال به علوه يدگر برنامههايي که آن برای انجام کارهای مفید ممکن ميسازد
4/322 محیط برنامه سازی لینوکس
ورود به سيستم
شما بايد يك نام و يك کلمه رمز ورودی داشته باشید ،شما ميتوانید اين نام را از اسم يا برنامه نرمافزاری سیستمتان بگیريد .سیستم
يونیکس قابلیت ارتباط با انواع وسیع پايانهها را دارد ،اما اين سیستم به طرز قابل توجهي در جهت ابزارهايي با حروف کوچك است،
يعني حروفي که مطالب را از يکديگر مجزا مي سازد ،اگر پايانه شما تنها حروف بزرگ ايجاد کند( ،مثل برخي از ويدئو و پايانه های
قابل حمل) زندگي آنچنان سخت خواهد شد که شما بايد به دنبال پايانه ديگری باشید .از دکمههايي که به طرز مناسبي بر روی وسیله
شما قرار گرفته است ،مطمئن شويد ،از حروف بزرگ و کوچك ،سیستم دو طرفه کامل و ديگر تجهیزاتي که کارشناسان به آنها توصیه
ميکندن ،مثل سرعت يا سرعت باود نیز اطمینان حاصل کنید .با استفاده از هر عمل شگفتانگیزی که برای پايانه شما نیاز است،
ارتباطي را ايجاد کنید ،اين فرايند ممکن است شامل ارتباط تلفني يا صرفا ً ضربه زدن به يك دکمه باشد .در موارد ديگر ،سیستم بايد
عمل تايپ را انجام دهد.
برقراري ارتباط
اگر سیستم اطلعات غیرمفید ،تايپ کند ،احتمال ً نشان دهنده اين است که شما سرعت غلطي را انتخاب کردهايد ،محیط مربوط به
سرعت را و نیز ديگر دکمهها را چك کنید .اگر اين کار فايده نداشت ،کلید breakيا interruptرا چند بار آهسته ،فشار دهید .اگر
هیچکدام از اين کارها پیام ارتباط را نمايان نکرد ،فرد متخصصي را به کمك بگیريد .زماني که شما ارتباط برقرار کرديد ،پیامي به اين
مضمون نمايان ميشود :
اسم ارتباطتان را با حروف کوچك تايپ کنید .به دنبال آن ،کلید Returnرا فشار دهید .اگر کلمه رمز نیاز باشد ،در مورد آن از شما
سؤال ميکند و عمل چاپ مادامي که شماآن را (کلمه رمز) تايپ ميکنید قطع ميشود .حداکثر تلشهای برقراری ارتباطتان به صورت
پیام واره انجام مي شود .معمولً به صورت يك علمت تنها ،پیام واره نشان دهنده اين است که سیستم برای پذيرش فرامیني از جانب
شما آماده است .پیام واره غالبا ً شبیه يك علمت دلر $يا علمت درصد ( )%است .پیام واره به وسیله برنامهای که مترجم (مفسر)
پیامها يا shellنامیده مشود ،چاپ مي شود که اين برنامه واسط اصلي شما برای سیستم به شمار ميآيد .شايد پیامي از روز قبل از پیام
کنوني موجود باشد يا اطلعیه ای مبني بر اين که شما نامه داريد وجود داشته باشد .شايد بپرسید که شما اکنون در حال استفاده از چه
نوع پايانهای هستید؟ پاسخ شما به سیستم برای استفاده از هر گونه خصوصیات که پايانه آنها را داراست ،کمك ميکند.
تايپ فرامين
زماني که شما پیام واره ای را دريافت ميکنید ،ميتوانید فرامیني را تايپ کنید که اين فرامین عبارتند از درخواستهايي که سیستم آنها را
انجام مي دهد .ما در نظر داريم که از برنامه ها به عنوان برنامههايي هم معنا و مشابه فرامین استفاده کنیم .سیستم بايد با زمان و تاريخ
پاسخ دهد .سپس پیام ديگری را چاپ کند ،بنابراين تمام مذاکرات شبیه به اين مورد در پايانه شما خواهد بود :
$ date
5/322 محیط برنامه سازی لینوکس
بعضي اوقات پايانه شما ممکن است به طرز غیر متداولي عمل کند ،برای مثال هر حرف ممکن است دو بار تايپ شود ،يا Return
ممکن است ،مکان نما را در ابتدای ستون خط بعدی قرار ندهد .شما معمول ً ميتوانید اين جريان را با خاموش و روشن نمودن پايانه
تثبیت کنید يا با خارج شدن از ارتباط و سپس برقراری در ارتباط مجدد .يا مي توانید توصیف فرمان ( STTyتنظیم انتخابهای پايانه) که
در بخش اول فهرست راهنما است ،را مطالعه کنید .به منظور کنترل ارتباطات از طريق مضخصه Tabدر صورتي که پايانه شما دارای
Tabsنباشد ،فرمان را تايپ کنید.
اگر شما خطای تايپي داشته باشید و آن را قبل از اينکه کلید Returnرا فشار دهید ،ببینید ،دو روش برای اصلح آن وجود دارد :
علئم پاك کردن در همان زمان يا از بین بردن تمام سطر و تايپ مجدد آن .اگر شما علمت از بین بردن سطر را تايپ کرده باشید (پیش
فرض علمت @ ) اين عمل باعث ميشود که تمام سطر حذف شود ،درست مثل زماني که شما هرگز آن سطر را تايپ نکرده بايد و يا
آن عمل (تايپ) را از سطر جديدی شروع کرده باشید:
@$ ddtae Completely botched;start over
date on a new line
Mon sep 26 12:23:39 EDT 1983
$
علمت sharp #باعث پاك کردن آخرين حرف /علمت تايپ شده ميشود ،هر #تنها يك حرف را پاك ميکند ،و به ابتدای سطر بر
مي گردد (البته نه فراتر از آن سطر) .بنابراين اگر شما اشتباهاً تايپ کنید ،شما ميتونید آن را به همین ترتیب اصلح نمائید.
$ dd#atte##e Fx it as you go
Mon sep 26 12:24:02 EDT 1983
$
پاكکنهای خاص و علئم از بین بردن سطر ،سیستمهای بسیار وابسته هستند .در بسیاری از سیستمها (از جمله سیستمي که ما از آن
استفاده ميکنیم) ،علمت پاك کن تغییر يافته است و تبديل به ( back spaceيا پسبرد) شده است ،که در پايانههای ويدئو به خوبي
عمل ميکند .شما سريع ًا ميتوانید متوجه شويد که کدام مورد سیستم شما قرار گرفته است :
میزان وسیع برای نشان دادن اين مطلب که علئم زير به طريقي خاص و ويژه هستند ،مورد استفاده قرار ميگیرد .به منظور پاك کردن
\ #آيا ميدانید چرا؟ علئمي که شما تايپ کرديد مورد بررسي قرار backslashشما بايد دو علمت پاكکن را تايپ کنید .يعني #
گرفته و بوسیله توالي برنامهها قبل از اينکه آنها به مقصدشان برسند ،تعبیر و تفسیر مي شوند.
و اينکه آنها دقیقا ً چگونه تعبیر و تفسیر ميشوند نه تنها به جايي که پايان مي پذيرند بستگي ندارد بلکه به چگونگي رسیدن به آن
مرحله نیز بستگي ندارد .هر علمتي را که تايپ ميکنید ،بلفاصله در قسمت پايانه انعکاس پیدا ميکند مگر اينکه روند انعکاسيابي
پايان پذيرد (پايانه خاموش شود) که اين شرايط بسیار نادر است .زمانیکه Returnرا فشار دهید علمتها به صورت موقتي توسط هسته
اصلي ( )kernelکنترل ميشوند ،در نتیجه غلطها تايپي ميتوانند با پاك کن و مشخصه از بین برنده سطرها ،تصحیح شوند .زماني که
پاك کن يا علمت از بین برنده سطر توسط backslashتقدم يابد ،هسته اصلي ( )kernelباعث ميشود که backslashکنار زده شده
و بقیه علمتها را بدون تعبیر و تفسیر کنترل کند .زمانیکه Returnرا فشار دهید ،علئم حفظ شده به برنامه ای فرستاده مي شوند که از
پايان خوانده ميشود .آن برنامه نیز به نوبه خود ممکن است علئم و مشخصهها را به روشهای خاصي تعبیر و تفسیر کند ،برای مثال:
برنامه shellهرگونه تعبیر خاصي از علئم را در صورتي که توسط backslashتقدم يافته باشد را از بین ميبرد .در مورد اين موضوع
در فصل 3بحث خواهیم کرد .اکنون ،بايد به خاطر داشته باشید که ( kernelهسته اصلي) پاكکن و علمت از بین برنده سطرها را
پردازش ميکند و backslashتنها در صورتیکه پاك کن و علمت از بین برنده سطر را در تقدم قرار داده باشد ،هر علمتي را که بعد از
آن رها شده باشد را به وسیله برنامههای ديگری به خوبي تعبیر و تفسیر مي کند.
@ \ dateچه اتفاقي ميافتد. تمرين 1ـ .1توضیح دهید در صورتي که $
تمرين 2ـ .1اغلب برنامههای ( shellاگر چه shellچاپ هفتم شامل آن نمي شود) علمت #را به عنوان معرفي به موضوع تعبیر
ميکنند ،و تمام متن را از علمت #تا پايان سطر ناديده ميگیرند .با توجه به اين موضوع ،نسخه زير را توضیح دهید ،فرض کنید که
علمت پاكکن نیز به صورت #است :
$ date
Mon sep 12 : 39 : 56 EDT 1983
$ # date
Mon sep 26 12 : 24: 21 EDT 1983
$ \ # date
$ \ \ # date
(يافت نشد) # date : not found
$
هسته اصلي ( )kernelآنچه را که شما تايپ مي کنید را همزمان با تايپ آن مي خواند ،حتي اگر هسته اصلي مشغول کار ديگری باشد،
بنابراين با سرعت مورد دلخواه مطلب مورد نظرتان را تايپ کنید ،و يا حتي هر زمان که ميخواهید ،حتي زماني که برخي از فرمانها به
نفع شما چاپ نشوند .در صورتیکه هنگام عمل چاپ سیستم ،شما تايپ انجام دهید ،علئم ورودی شما در ترکیب با علئم خروجي به
نظر ميرسند اما ،آنها ذخیره شده و به ترتیب صحیح تفسیر مي شوند .ميتوانید فرامین را يکي پس از ديگری بدون انتظار کشیدن برای
اتمام آنها يا حتي شروع آنها ،تايپ کنید.
8/322 محیط برنامه سازی لینوکس
توقف برنامه
شما ميتوانید اغلب فرامین را با تايپ علمت deleteمتوقف سازيد .کلید Breakکه در اغلب پايانهها يافت ميشوند نیز ميتواند اين
کار را انجام دهد ،اگر چه اين عمل به سیستم بستگي دارد .در چندين برنامه همچون برنامه ويراستاری متن ،کلید deleteهر آنچه را که
برنامه انجام داده است را متوقف ميسازد اما شما را در آن برنامه رها ميکند .خاموش کردن پايانه يا برداشتن تلفن ،اغلب برنامهها را
متوقف ميسازد .اگر شما تنها بخواهید از حالت توقف بیرون آئید ،برای مثال :برای حفظ برخي از مسائل ضروری از ناپديد شدن در
صفحه نمايش ،فرمان CTL-Sرا تايپ کنید .فرايند بازدهي تقريبا ً سريع متوقف مي شود ،بدين ترتیب برنامه شما موقتاً تا زمانیکه شما
دوباره آن را شروع کنید ،متوقف ميشود .زمانیکه شما بخواهید دوباره برنامه را ادامه دهید ،فرمان CTL-qرا تايپ کنید.
ار دادن deleteخارج شويد .توجه کنید که خطاهای تايپي شما بر روی پايانه مری ظاهر نمي شود .اگر شما در نظر داريد که به فردی
که در ارتباط نیست نامه بنويید يا به فردی که نمي خواهد با کراه مناسب برای قطع کردن ارتباط عبارتست از تايپ فرمان CTL-dبه
جای فرمان وجود ندارد .به منظور پاسخ دهي ،فرمان write Mary $را تايپ کنید .اين عمل مسیر ارتباطي دو طرفهايي را بوجود
ميآورد .اکنون سطرهايي را که مری بر روی پايانه خودش تايپ کرده بر روی پايانه شما نیز تايپ ميشود و بر عکس ،اگر چه اين
مسیر آرام و آهسته عمل ميکند اما تا حدی بیه به talking to the moonاست .اگر در اواسط کاری قرار داريد ،شما مجبوريد در
شرايطي قرار گیريد که بتوانید فرماني را تايپ کنید .طبیعتاً هر برنامه ايي که شما در حال اجرای آن هستید بايد متوقف شود اما برخي از
برنامهها همچون ويراستار ياـ writeبه خودی خود ،دارای فرمانـ ( ! ) هستند که اين فرمان به طور موقتي از برنامهـ shellخارج
ميشود ،جدول 2را در قسمت ضمیمه 1مورد مطالعه قرار دهید .فرمان writeهیچ قانوني را وضع نمي کند ،بنابراين برای حفظ آنچه
تايپ ميکنیم و جلوگیری از مخدوش شدن با آنچه که مری تايپ ميکند ،دستورالعملي لزم است .يك قانون اين است که چرخشي
کرده و هر چرخش را با ( ) 0پايان دهد که اين علمت برای کلمه ( )overدر نظر گرفته شده و برای مشخص نمودن هدفتان ،با
علمت ( ،)00آن را متوقف سازيد و از آن خارج شويد ،اين علمت برای outو overدر نظر گرفته شده است.
بنابراين برای حفظ آنچه تايپ ميکنیم و جلوگیری از مخدوش شدن با آنچه که مری تايپ ميکند ،دستورالعملي لزم است .يك قانون
اين است که چرخشي کرده و هر چرخش را با ( ) 0پايان دهد که اين علمت برای کلمه ( )overدر نظر گرفته شده و برای مشخص
نمودن هدفتان ،با علمت ( ،)00آن را متوقف سازيد و از آن خارج شويد ،اين علمت برای outو overدر نظر گرفته شده است.
سي ارتباط داشته باشد ،در اين صوسي ارتباط داشته باشد ،در اين صورت بايد به شما بگويد .در صورتیکه هدف مورد نظر ارتباط
برقرار کرده باشد اما پس از يك وقفه مناسب پاسخ ندهد ،در اين صورت اين فرد ممکن است مشغول کاری بوده و يا از پايانه دور بوده
باشد ،در اين حالت CTl-dيا deleteرا تايپ کنید .اگر ميخواهید فردی مزاحم شما نشود ،از فرمان )mesg)1استفاده کنید.
اخبار
بسیاری از سیستمهای يونیکس ،سرويسهای خبری دارند ،و به اين ترتیب کاربران را پهلو به پهلوی وقايع جالب و نه چندان جالب
حفظ مي کنند .فرمان news $را تايپ کنید .همچنین شبکه وسیعي از سیستمهای يونیکس وجود دارد که از طريق خطوط تلفن در
تماس قرار ميگیرند ،در مورد شبکههای خبری و useNetاز يك کارشناس سؤال کنید.
فهرست راهنما
راهنمای برنامهساز يونیکس اغلب آنچه را که شما نیازمند دانستن پیرامون سیستم هستید را توصیف ميکند .بخش ،1با فرامین ارتباط
دارد يعني شامل فرامیني است که ما در اين بخش در مورد آنها بحث ميکنیم .بخش ،2سیستم صوت را توصیف ميکند ،موضوع فصل
7و بخش ، 6اطلعاتي پیرامون بازيها دارد .ما بقي بخشها در مورد نقشهای استفاده از برنامه هایـ ، Cفرمت فايل و حفظ سیستم
صحبت مي کند( .تعداد اين بخشها از سیستمي به سیستم ديگر فرق مي کند).
فهرستهای جابه جا شده در ابتدای کتاب راهنما را فراموش نکنید ،شما ميتوانید سريعاً از آن گذشته و برای فرامیني که ممکن است به
آنچه که شما ميخواهید انجام دهید مربوط باشد ،مطالعهای گذرا از آن انجام دهید .همچنین مقدمهای در مورد سیستم وجود دارد که
اطلعاتي در مورد چگونگي عملکرد آن ارائه مي دهد .غالباً فهرست راهنما بر روی خط حفظ ميشود ،بنابراين ،شما ميتوانید آن را از
طريق پايانه خودتان مطالعه کنید .اگر شما غرق در کاری شديد و نتوانستید فرد متخصصي را به کمك بگیريد ،مي توانید صفحه
فهرست راهنما را بر روی پايانه خودتان با فرمان man comman-nameچاپ کنید.
بنابراين برای اطلع از اينکه فرمان چه کسي بوده است :فرمان
ديگری; و اين موضوع به shellميگويد که ورودی مسیر ديگری موجود نميباشد (.اينکه چگونه اين عمل واقعاً صورت ميپذيرد در
فصل بعدی توضیح داده ميشود) معمول ميتوانید پايانه را خاموش و يا گوشي تلفن را برداريد اما ،اين که اين عمل واقعاً ارتباط شما
را قطع ميکند يا نه ،به سیستم تان بستگي دارد.
10/322 محیط برنامه سازی لینوکس
پست الكترونيك
سیستم باعث ميشود تا سیستم پستي جهت برقراری با کار بر ديگری ،فراهم شود .بنابراين در صورتیکه روزی ارتباط برقرار شود شما
و پیام زير را خواهید ديد:
«نامه داريد»
واين پیغام را قبل از اولین برقراری ارتباط خواهید ديد .به منظور خواندن نامهتان فرمان mail$را تايپ کنید .نامة شما چاپ خواهد
شد و پیامي که پديدار ميشود به عنوان اولین و جديدترين پیام است .بعد از هر عنوان نامه صبر کنید تا شما آنچه را که ميخواهید در
مورد آن اجرا کنید را اعلم کنید .دو جواب اصلي عبارتند از dکه اين جواب پیغام را حذف کنید و ديگری Returnکه کاری انجام
نميدهد ( بنابراين نامه باقي ميماند تا هر زمان ديگری که خواستید نامهتان را بخوانید) جوابهای ديگر عبارتند از Pکه باعث ميشود
پیغام دوباره چاپ شود ،نام فايل Sکه باعث ميشود نامه در فايلي که شما به آن نام دادهايد ذخیره شود و qکه برای رد شدن از نامه،
طراحي شده است( .در صورتیکه شما ندانید که يك فايل شامل چه چیزی است به فکر مکان خاصي باشید که بتوانید اطلعات را
تحت يك نام انتخابي ذخیره کنیدو آن را بعدا بازيابي کنید .فايلها موضوع بخش 102بوده و در واقع بخش عظیمي از کتاب را به خود
اختصاص دادهاند .پست الکترونیکي يکي از آن برنامههايي است که احتمال ً متفاوت از آنچه ميباشد که ما در اينجا توصیف ميکنیم .
انواع بسیارزيادی از آنها وجود دارد .جهت اطلع از جزئیات به کتاب راهنما مراجعه کنید .فرستادن نامه به افراد کار سادهای است.
فرض کنید نامه به فردی با نام ارتباطي nicoفرستاده ميشود .راحت ترين وسادهترين روش عبارتست از:
$ mail nico
اکنون در متن نامه هر تعداد سطری که ميخواهید تايپ کنید بعد از آخرين سطر نامه فرمان Gntrd-dرا تايپ کنید.
$Ctl – d
Ctl-dبه معنای پايان نامه به وسیله فرمان mailاست که بیان ميدارد هیچ ورودی ديگری موجود نميباشد اگر شما در نیمة راه
نظرتان را مبني بر ترکیب نامه تغییر داديد ،کلید deleteرا به جای ctl-dفشار دهید .نامهای که به صورت نیمه کاره شکل گرفته است
در فايلي که به نام dead.letterاست به جای فرمان انتقال ( )Sendذخیره ميشود .به عنوان تمرين،نامهای را برای خودتان بفرستید،
سپس،علمت mailرا جهت خواندن نامه تايپ کنید.
(اين عمل به آن اندازهای که به نظر ميرسد گمراه کننده نیست ،اين کار مکانیسم يادآوری مناسبي است) .روشهای ديگری برای
فرستادن نامه وجود دارد شما ميتوانید نامهای را که از قبل آماده شده است را بفرستید ،ميتوانید نامهای را به تعدادی از افراد مورد
نظرتان در يك زمان خاص بفرستید و ممکن است قادر باشید نامه را به افرادی در سیستمهای ديگر بفرستید .جهت اطلع از جزئیات
بیشتر نسخه فرمان mailرا در بخش 1فهرست راهنمای برنامهساز يونیکس مطالعه کنید .از اينجا به بعد ما از مفهم ( mail )1به معنای
صفحاتي که mailرا در بخش 1کتاب راهنما توصیف ميکنند ،استفاده ميکنیم همچنین ممکن است سرويس تقويم نیز وجود داشته
باشد ( بخش ،تقويم 1را مطالعه کنید) و ما در فصل 4به شما نشان خواهیم داد که نامه چگونه در صورتي که پیش از اين کاری بر
روی آن انجام نگرفته است ،تنظیم ميشود.
از سیستم يونیکس شما دارای چندين کاربر است .روزی ،ناگهان.پايانه شما پیغامي شبیه به اين موضوع چاپ خواهد کرد:
11/322 محیط برنامه سازی لینوکس
بازيها
بازيها همیشه پذيرفته شده نیستند امايکي از بهترين راهها برای کسب آسايش و راحتي از کامپیوترها و پايانهها ،اجرای بازيها است.
سیستم يونیکس با تجهیزات معمولي از بازيها همراه است و غالبا ً اين تجهیزات به صورت محلي ضمیمه ميشوند .اطراف را مورد
بررسي قرارداده يا بخش 6فهرست راهنما را مورد مطالعه قرار دهید.
اطلعات در سیستم يونیکس در فايلها ذخیره ميشود ،که بیشتر شبیه به فايلهای اداری معمولي هستند .هر فايل دارای نام ،محتوا و
مکاني برای حفظ آن است و برخي از اطلعات اداری ( اجرايي) همچون فردی که مالك آن است و میزان بزرگي آن ،ميباشد فايل
ممکن است دارای نامه يا لیستي از نامها و آدرسها باشد يا منبع اطلعات برنامهها يا اطلعاتي که بايد به به وسیله برنامه استفاده شود يا
حتي دارای برنامه ها به شکل قابل توجیه و ديگر موضوعات غیر متني باشد .فايل سیستم يونیکس به صورت سازمان يافته است.
بنابراين شما ميتوانید فايلهای شخصي خودتان را بدون مداخلت با فايلهای متعلق به افراد ديگر حفظ کنید و افراد را از دخالت پیدا
کردن در مورد فايلهای خودتان منع نمائید .تعداد زيادی برنامه وجود دارد که فايلها را کنترل ميکند .اما اکنون ما تنها به اکثر آنهايي که
به طور مکرر توسط افراد مورد استفاده قرار ميگیرد ،سرورکار داريم .فصل 2شامل بحث سیستماتیکي در مورد فايل سیستم است و
بسیاری از ديگر فرامین مربوط به فايلها را معرفي ميکند.
ايجاد فايل ـ فايل ويراستار
در صورتي که بخواهید برگه يا نامه و يا يك برنامه را تايپ نمائید .چگونه اطلعات ذخیره شده در ماشینـ ( سیستم) را بدست
ميآوريد؟
اغلب اين کارها با فايل ويراستار متن که برنامهای برای ذخیره کردن و کنترل اطلعات در کامپیوتر است انجام ميگیرد ،تقريبا ً هر
سیستم يونیکس دارای ويراستار صفحه نمايش است ويراستاری که مزيتهايي را از پايانههای مدرن گرفته وبدين وسیله تأثیرات تغییرات
ويراستاری شما را در متن همزمان با بوجود آوردن متن ،نشان ميدهد .دو نمونه از مشهورترين اين فايلها عبارتند از emacs,viما در
12/322 محیط برنامه سازی لینوکس
نظر نداريم که هیچ نوع ويراستار صفحه نمايش خاصي را در اينجا تشريح کنیم ،و اين امر تا حدی به دلیل محدوديتهای حروف چیني
و تا حدی به دلیل عدم وود نوعي استاندارد است .با اين وجود يك نمونه ويراستار قديميتر که edنامیده ميشود وجود دارد که
مطمئنا ً برروی سیستم شما موجود است .اين نوع ويراستار هیچ گونه مزيتي از خصوصیات پايانههای دريافت نکرده است ،بنابراين بر
روی هر گونه پايانهای کار خواهد کرد .اين فايل همچنین اصولي از ديگر برنامههای ضروری را تشکیل ميدهد( شامل برخي از
ويراستارهای صفحه نمايش ) بنابراين فايل ارزش يادگیری را دارد .ضمیمه 1شامل نسخة مختصری از اين فايل است .اين که شما چه
نوع ويراستاری را ترجیح ميدهید مهم نیست ،بلکه مهم است که شما آن را به خوبي فرا گرفته تا بتوانید فايلهايي را ايجاد نمائید .در
اينجا ما از فايل edجهت ارائه بحث استفاده ميکنیم و مطمئن هستیم که شما ميتوانید مثالهای ما را بر روی سیستمتان اجرا نمائید اما
حتما ً از ويراستاری که بهتر دوست داريد استفاده نمائید .به منظور استفاده از edجهت ايجاد فايلي که junkنامیده ميشود ( به همراه
متوني در آن ) کارهای زير را انجام دهید:
ed $ فرمان edويراستار متن را به منظور
افزودن متن به کمك بطلبید a
اكنون در هر متني كه ميخواهيد
تايپ کنید.
•
w junk ‘ را به منظور متوقف نمودن . به وسيله خودش ’
39 افزايش متن،تايپ کنید .متن تان را در فايلي که
ed تحت عنوان junkاست،بنويسیدq .
$ تعدادی از علئم نوشته شده را چاپ ميکند.
از edخارج شويد.
فرمان ’’( aضمیمه سازی ‘‘( به edميگويد شروع به جمعآوری متن کند.
‘‘ که نشان دهنة پايان متن است بايد در شروع خط ( سطر) به وسیله خودش تايپ شود .آن را تازمانیکه تايپ ’’ .
شود فراموش نکنید .ديگر فرامین edنبايد سازماندهي شوند هر چیزی که شما تايپ ميکنید مادامي که متن افزوده
ميشود مورد بررسي و کنترل قرار خواهد گرفت ) فرمان ويراستاری ”( wنوشتن“) اطلعاتي را که شما تايپ ميکنید
را ذخیره ميکند’’ “ w junkآن را در فايلي که junkنامیده ميشود و ما junkرا از اين رو انتخاب کردهايم تا پیشنهاد
کنیم که اين فايل خیلي مهم نیست Ed .با تعدادی از علئمي که آن را در فايل قرار ميدهد پاسخ ميدهد .تا زمانیکه
wفرمان ندهد ،هیچ چیزی به صورت دائمي ذخیره نميشود بنابراين اگر شما گوش را گذاشته و به خانه برويد،
اطلعات در فايل ذخیره شده است ( .اگر شما گوشي را مادامي که در حال ويرايش هست بگذاريد ،اطلعاتي که
درحال پردازش است ،در فايلي که ed.hupنامیده ميشود ذخیره ميشود که بدين ترتیب شما ميتوانید به فعالیت
متني خودتان ادامه دهید ).اگر سیستم دچار سروصدا شد( برای مثال به صورت غیرمنتظره و به دلي اشکالت سخت
افزاری و نرم افزاری بايستید) البته زمانیکه شما در حال ويراستاری هستید ،فايل شما تنها دارای آنچیزی است که
13/322 محیط برنامه سازی لینوکس
آخرين فرمان نوشتاری آنجا قرار داده است .اما پس از اينکه ( wنوشتن) اطلعات به صورت دائمي ثبت شد ،شما
ميتوانید بعداً با تايپ فرمان ed junk $دوباره به آنها دسترسي پیدا کنید البته ميتوانید متني را که شما تايپ کردهايد
را ويراستاری کنید و يا خطاهای امليي آن را تصحیح نمائید .کلمات را تغییر دهید ،پاراگرافها را دوباره مرتب کنید
و کارهايي از اين قبیل ،زماني که شما اين کارها را نجام داديد،فرمان ( qخروج) اعلم ميدارد که از فايل ويراستاری
خارج شويد.
چه فايلهايي خارج از برنامه هستند؟
اجازه دهید دو فايل ايجاد کنیم فايل Temp , junkبنابراين ما آنچه را که داريم ميشناسیم.
$ ed
a
باشد يا نباشد
•
W junk
19
q
$ ed
A
سوالي مطرح است
•
w Temp
22
q
$
علمتي که از edمنظور ميشود عبارتست از علمتي در پايان هر خط (سطر) و که خط جديد يا سطر جديد نامیده ميشود اين علمت
چگونگي نشان دادن Returnسیستم را نشان ميدهد .فرمان ( 1sنه محتوا) از فايلها را فهرست ميکند:
$ 1s
junk
Temp
$
که اين نامها ،دوفايلي هستند که تنها ايجاد شدهاند( ممکن است فايلهای ديگری نیزوجود داشته باشند که شما ايجاد نکرده باشید) نامها
به ترتیب حروف الفبايي به صورت اتوماتیك طبقه بندی ميشوند 1s .شبیه اغلب فرامین ،دارای انتخابهايي است که ممکن است برای
تغییر رفتارهای غلط به کار برده شوند .انتخابها نام فرامین را در سطر فرمانها پي گیری ميکنند و معمول از علمت تفريق’ ــ ‘ و از يك
حرف تنها که معمولً دارای معنا است ،تشکیل شده است .برای مثال 1s-t ،باعث ميشود که فايلها به ترتیب زماني فهرست شوند:
ترتیبي که در آن آنهايي که آخر تغییر يافتهاند غالب ًا جديدتر بوده و در اولويت آخر هستند.
$ 1s-t
Temp
Junk
$
انتخاب 1ـ فهرست طويلي را نشان ميدهد که اطلعات زيادی در مورد هر فايل فراهم ميآورد.
14/322 محیط برنامه سازی لینوکس
$ 1s-1
Total 2
- rw-r- - r- - 1 jou 19 sep 26 16:25 junk
- rw - r - - r - - 22 sep 26 16:26 Temp
- rw-r - - r - -
" " total 2نشان ميدهد که چه تعداد از بلوکهای فضای ديسك در يك فايل اشغال شده است و يك بلوك معمول ً شامل 512يا
1024کاراکتر است.
رديف - - rw r - - r -نشان ميدهد که چه کسي اجازه خواندن و نوشتن در يك فايل را دارد .در اين مورد مالك اصلي ( شما )
ميتوانید بخوانید و بنويسید ،اما ديگران تنها ميتوانند آن فايل را بخوانند عدد " "1که به دنبال آن ميآيد نشان دهنده تعداد ارتباط به
فايل است از اين موضوع تا رسیدن به فصل 2صرفنظر کنید " .شما " مالك فايل هستید ،يعني ،فردی که آن فايل را ايجاد کرده
است 22 .و 19تعداد کاراکترهايي است که با فايلها در مکاتبه بودند .که اين تعداد با تعدادی که شما از فايل edدريافت کردهايد،
هماهنگي دارد .تاريخ وزمان نشان ميدهد که چه زماني فايل آخرين تغییر را پیدا کرده است انتخابها ميتواند گروهبندی شود1s, 1t :
دادههايي همانند 1s-1را ارائه ميدهد اما بر اساس آخرين فايلها طبقه بندی ميشود .انتخاب – uاطلعاتي را در مورد زمان خاصي که
فايل مورد استفاده قرار گرفته است ارائه ميدهد:
1s - 1utلیست طولي ( )1-را به ترتیب آخرين استفاده نشان ميدهد .انتخاب مورد r -ترتیب خروجي را بر عکس ميکند .بنابراين،
1s-rtبه ترتیب آخرين مورد استفاده شده فهرست ميشود .همچنین شما ميتوانید فايلها را به نامهايي که مورد علقهتان است ،نام
گذاری کنید و 1sتنها اطلعاتي در مورد خودشان را ،فهرست ميکنند:
$ 1s - 1 junk
- rw -r - - r - - 1jou 19 sep 26 16:25 junk
$
رديف يا رشتههايي که برنامهها را ادامه ميدهند بر اساس سطر فرمان نام گذاری ميشوند ،مثل junk , -1در نمونه بال،اين موارد
تحت عنوان «شناسنامه برنامه » نام گذاری و شناخته ميشوند .شناسهها معمول ً شامل انتخابها يا نامهای فايلهايي هستند که بوسیله
فرمانها مورد استفاده قرار ميگیرند .انتخابها را به وسیله علمت منها (ـ ) و يك حرف تنها مشخص کنید مثل t -يا به صورت ترکیبي -
1tکه اين مورد بیشتر شايع است .به طور کلي در صورتیکه يك فرمان پذيرفته شود ،مثل شناسه انتخابي ،آنها هر گونه شناسه نام فايلها
را در تقدم قرار ميدهند اما ممکن است در هر ترتیب ديگری جور ديگری به نظر برسد .اما برنامههای يونیکس در کنترلشان پیرامون
انتخابهای چندگانه،بي نظم هستند .برای مثال هفتمین چاپ استاندارد 1sمورد زی را
1s - 1 -t $ در چاپ هفتم فعال نمي باشد
به عنوان معادلي برای 1s-1tنميپذيرد ،هر چند دنبال برنامهها نیازمندند انتخابهای چند گانه جهت مجزا شدن مي باشند.
مادامي که اطلعات بیشتری فراگیريد ،متوجه خواهید شد که نظم کم وجود داشته يا سیستم در حالت شناسه انتخابي قراردارد .هر زمان
دارای ويژگي منحصر به فرد خود و انتخاب های مخصوص به خود در مورد آن خروجي که به معنای آن است ميباشد ( غالبا ً اين
موارد متفاوت از همان نقش در فرامین ديگر مي باشند) اين رفتارهای غیرقابل پیش بیني آزار دهنده بوده و غالبا ً به عنوان نقصان و
ضعف بزرگي در يك سیستم .مطرح ميباشند .اگر چه اين شرايط در حال بهبوديابي هستند ( انواع جديد غالب ًا دارای يکنواختي بیشتری
ميباشد) و ما تمام آنچه که ما ميتوانیم پیشنهاد کنیم اين است که شما تلش کنید تا زمانیکه که در برنامه شخصیتان چیزی مينويسید
به بهترين نحو اين کار را انجام دهید و در اين میان يك کپي ازمهارتتان را حفظ کنید .
15/322 محیط برنامه سازی لینوکس
انتقال ،كپي ،پاك كردن فايلهاmr,cp ,rm
اجازه دهيد به فرامين ديگري نيز بپردازيم .اولين موضوع اين است كه نام فايل را عوض
كنيم نامگذاري جديد يك فايل به وسيله " انتقال" آن از يك نام به نام ديگر انجام ميپذيرد .مثل
اين مورد:
mv junk precious $
اين مورد به اين معناست که فايلي که برای نامیدن junkبه کار رفته است ،اکنون تحت عنوان preciousميباشد و محتوای آنها تغییر
نکرده است .اگر شما 1Sرا اکنون اجراکنید ،فهرست متفاوتي را خواهید ديد junk :ديگر وجود ندارد اما preciousموجود ميباشد.
$ 1s
Precious
Temp
$ cat junk
cat con,t open junk
$
آگاه باشید که اگر فايلي را به فايل ديگری که از قبل وجود داشته است انتقال دهید فايل مورد نظر ،جايگزين ميشود .به منظور گرفتن
کپي از فايل ( يعني داشتن دو نسخه از چیزی) از فرمان cpاستفاده کنید:
$ cp percious percious save
کپي دوتايي از perciousاز Percious.saveتهیه کنید.
نهايتا ً زماني که ما از ايجاد و انتقال فايلها خسته شديد ،فرمان ، rmتمام فايلهايي را که شما نامگاری کردهايد را پاك ميکند rm $ .
17/322 محیط برنامه سازی لینوکس
Temp junk
Rm:junk nenexistent
$
در صورتیکه يکي از فايلهايي که بايد پاك شود موجود نباشد ،بايد اطلع داشته باشید اما rmمثل اغلب فرامین يونیکس اين کار را به
آرامي انجام ميدهد .هیچ دای ناموزوني در اين حین به گوش نميرسد و پیغامهای خطا محدود بوده و بعضي اوقات سودند لغي باشند.
خلصه نويسي ميتواند برای افراد تازه وارد ،دردسرساز باشد اما کاربران با تجربه فرامین طويل وپرحرف را آزار دهنده تلقي ميکنند.
تاکنون از نام فايلها بدون اينکه بگويیم يك نام قانوني چیست؟ استفاده کردهايم ،اکنون زمان مجموعهای از قوانین است اول اينکه نامهای
فايلها به 14کاراکتر محدود ميباشند .دوم اينکه ،اگر چه ميتوانید تقريباً از هر کاراکتری در نامگذاری فايل استفاده کنید اما عقل سلیم
ميگويد شما بايد به کاراکترهايي متوجه شويد که مشهود هستند و از کاراکترهايي که ممکن است به ديگر معناها به کار روند،
بپرهیزيد .برای مثال ،پیش از اين ديديم که در فرمان 1s-t , 1 sبه معنای فهرست فايلها به ترتیب زماني است .بنابراين اگر شما فايلي
داريد که نام آن t -باشد در نتیجه برای فهرست آن بر اساس نام وقت زيادی بايد صرف کنید ( .چگونه بايد اين کار را انجام دهید)
علوه بر علمت منها(ـ ) به عنوان اولین کاراکتر ،کاراکترهای ديگری با معنای خاص وجود دارد .به منظور اجتناب از ايجاد مشکل ،بايد
در استفاده از حروف تنها ،اعداد ،دوره و زير خط دار کردن تا زمانیکه با موقعیت آشنايي پیدا کنید ،به خوبي و با احتیاط عمل کنید (
دوره و زير خط دار کردن )under scoreبه صورت قراردادی به منظور تقسیم نام فايلها به بخشهايي همچون Precious. Saveمورد
استفاده قرار ميگیرد) نهايتا ً فراموش نکنید که هر مورد ،موضوع مجزايي به شمار ميرود ،برای مثال Junk , Junk, junkهر کدام سه
نام متفاوت ميباشد.
اکنون که شما از اصول ايجاد فايل ،فهرست نامهای آنها و چاپ محتويات آنها اطلع پیدا کرديد،ميتوانیم شش مورد از فرامین پردازش
فايلها را مورد بررسي قرار دهیم .به منظور اينکه بحث جدی داشته باشیم .از فايلي استفاده خواهیم کرد که (شعر) poemنام دارد و
حاوی شعر مشهوری از Augustus de morganاست.
اجازه دهید اين فايل را با edايجاد کنیم.
$ ed
a
Great fleas have little fleas
Upon their back to bite em,
And little fleas have lesser fleas,
And so ad infinitum.
And the great fleas themselves , in turn
Have greater fleas to go on
18/322 محیط برنامه سازی لینوکس
And so ad infinitum.
Have greater fleas To go on,
Upon their backs to bite,em,
And little fleas have lesser fleas,
And the greater fleas themselves , in Turn,
great fleas have little fleas,
while these again greater still,
$
طبقه بندي به صورت سطر به سطر است اما ،ترتيب طبقهبندي ناقص باعث ميشود كه
در ابتدا جاي خالي قرار گيرد ،سپس حروف بزرگ و سپس حروف كوچك،بنابراين اين
شرايط دقيقًا براساس الفبا نميباشد sortداراي هزاران انتخاب جهت كنترل ترتيب طبقهبندي
است كه عبارتند از:
ترتیب معکوس،ترتیب عددی ،ترتیب لغت نامهای ،ناديده گرفن فضاهای خالي مهم ،طبقهبندی بر اساس فايلهای درون سطر و غیره اما
معمول فرد بايد جهت اطمینان از آنها ،آن انتخابها را بررسي کند .در اينجا ،فهرستي از معمولترين طبقه بندی وجود دارد.
Sort - v معکوس کردن ترتیب معمولي
Sort - n طبقه بندی به ترتیب عددی
Sort - nr طبقه بندی به ترتیب عددی معکوس
Sort-f Fold upperو حروف کوچك با هم ديگر
n+1-st Sort +n شروع طبقه بندی در میدان
فصل 4دارای اطلعات بیشتری پیرامون Sortاست.
فرمان بررسي فايل ديگری نیز وجود دارد که تحت عنوان Tailاست که 10سطر آخر فايل را چاپ ميکند .اين فرمان برای هشت
سطر شعر ما کفايت ميکند .اما بريا فايلهای بزرگتر مناسب است .علوه بر اين Tail ،برای مشخص نمودن تعدادسطرها دارای انتخاب
است ،بنابراين به منظور چاپ آخرين سطر شعر:
$ Tail -1 poem
and greater still,and so on
$
Tailهمچنین ميتواند برای چاپ فايلي که در يك سطر مشخص شده شروع ميشود ،به کار برده شوند:
$ tail +3 filename
چاپ با خط سوم شروع ميشود ( به معکوس بودن طبیعي علمت منها برای شناسهها توجه کنید) جفت فرامین نهايي برای مقايسه
فايلها در نظر گرفته شدهاند .فرض کنید که ما نوعي شعر در فايل New – poemداريم:
$ cat poem
Great fleas have little fleas
upon their back to bite em ,
And little fleas have leser fleas,
and so ad infinitum.
And the great fleas themselves , in turn,
Have greater fleas to go on,
While these again have greater still,
And greater still , and so on.
20/322 محیط برنامه سازی لینوکس
اين فرمان ميگويد که اين فايلها در سطر دوم از يکديگر متفاوتند که اين مورد کامل صحیح است .اما اين فرمان نميگويد که تفاوت
در چیست و علوه بر اين هیچ گونه از تفاوتهايي را که وجود دارد مشخص نميکند يکي ديگر از فرامین مقايسه فايلها فرمان diff
است که در مورد تمام سطرهايي که تغییر يافتهاند ،اضافه شدهاند و يا حذف شدهاند ،گزارش ميدهد:
$ diff poem new-poem
2c2
< upon their backs to bileem,
…
>upon Their backs to bite them,
4 c4
<and so ad infinitum.
…
>and so on ad infinitum.
$
اين فرمان ميگويد که سطر 2در اولین فايل ( فايل شعر) به سطر 2فايل ( شعرجديد) تغییر يافته است و به همین صورت در مورد
سطر چهارم .به طور کليـ cmpزماني استفاده ميشود که شما بخواهید مطمئن شويد که دو فايل به طور واقعي دارای يك محتوا
هستند .کار اين فرمان سريع بوده و در هر نوع فايلي کار ميکند نه در متن تنها diffزماني استفاده ميشود که فايلها تا حدی متفاوت به
نظر برسند و شما بخواهید واقع ًا بدانید که کدام سطر متفاوت است .فرمان diffتنها در فايلهای متني اجرا ميشود.
جدول 1-1خلصهای از فرامیني است که ما تاکنون در ارتباط با فايلها از آنها صحبت کردهايم.
سیستم فايل شما را که تحت عنوانـ junkاست ازفايل فرد ديگری که به همین نام است،متمايز ميشناسد .اين تمايز به وسیله
21/322 محیط برنامه سازی لینوکس
گروهبندی فايلها به فهرستها ،صورت ميپذيرد که اين فرآيند نسبتاً به ترتیبي است که کتابها در کتابخانهها بر روی قفسهها جای داده مي
شوند ،بنابراين فايلهايي که در فهرستهای متفاوت هستند ميتوانند بدون هیچ گونه تضادی دارای يك نام باشند .به طور کلي هر کاربر
دارای يك فهرست شخصي و خصوصي است ،بعضي اوقات تحت عنوان فهرست loginاز آن ياد ميشود ،که تنها حاوی فايلهايي
است که متعلق به آن فرد است .زماني که شما با سیستم ارتباط برقرار ميکنید ،در واقع شما در فهرست شخصي خودتان هستید.
ممکن است فهرستي را که شما در حال کارکردن در آن هستید را تغییر دهید غالباً فهرست کنوني و آن فهرستي را که در حال فعالیت بر
روی آن هستید را مشخص کنید اما در اين شرايط فهرست شخصي شما هنوز به همان صورت قبلي باقي است .مگر اينکه شما عمل
خاصي را انجام دهید مثلً زمانیکه يك فايل جديد ايجاد کنید در واقع اين فايل وارد فهرست کنوني شما ميشود از آنجايي که اين فايل
به عنوان فهرست شخصي شما است ،در واقع اين فايل به فايلي با همان نام که ممکن است در فهرست شخص ديگری باشد ،در واقع
اين فايل به فايلي با همان نام که ممکن است در فهرست شخص ديگری باشد ،مربوط نميشود .فهرست ميتواند حاوی فهرستهای
ديگر و نیز افیلهای معمولي باشد (فهرستهای بزرگ دارای فهرستهای کوچکتر هستند).
روش معمول برای به تصوير کشیدن اين سازماندهي شبیه به درختي از فهرستها و فايلها است .اين امکان وجود دارد که پیرامون هر
کدام از اين درختها حرکت کرده و هر کدام از اين فايلهای درون سیستم را به وسیله شروع مسیر از ريشه درخت و حرکت به دنبال
شاخههای مناسب ،پیداکنیم .بر عکس شما ميتوانید از جايي که در آن قرار گرفتهايد شروع کرده و به سمت ريشه حرکت کنید .اجازه
دهید که مورد اخیر را اول انجام دهیم .ابزار اصلي ما فرمان pwdاست( فهرست فعالیت چاپ) که نام فهرستهايي را که شما اکنون در
آنها هستید را چاپ ميکند:
22/322 محیط برنامه سازی لینوکس
اين فرمان ميگويد که شما در حال حاضر در فهرست خودتان و در دايرکتوری usrهستید که به نوبة خود اين فهرست در فهرست
ريشه قرار دارد ،که اين فهرست به صورت قراردادی «م» نامیده ميشود .علمت /اجزاء نام را از يکديگر جدا ميکند؛ محدودة 14
کاراکتری که در بال ذکر شد برای هر جزء که چنین نامي حاوی فهرستهای تمام کاربردن سیستم است ( .حتي اگر فهرست اصلي شما به
صورت usr/you/نباشد ،در اين صورت pwdچیزی شبیه به آن را چاپ خواهد کرد و بنابراين شما بايد قادر باشید ،آنچه را که در
زير اتفاق ميافتد ،پیگیری کنید) .اگر اکنون شما
1S/usr/youرا تايپ کنید ،دقیقا ً همان فهرست نامهای فايلي را دريافت ميکنید که شبیه به آنچه ميباشد که از 1Sمعمولي $
دريافت کردهايد .زمانیکه هیچ شناسهای فراهم نباشد و 1Sمحتواهای فهرستهای معمول را فهرست ميکند ،و نام دايرکتوريها را نشان
1S/usrتلش کنید ،اين فرمان بايد يك سری طويلي از مي دهد و محتوای آن دايرکتوری را فهرست ميکند .سپس برای اجرای $
نامها را چاپ کنید که در بین آنها دايرکتوری متعلق به شما نیز وجود دارد .مرحلة بعدی تلش برای فهرست کردن خود ريشه است .در
اين وضعیت جوابي شبیه به اين نمونه دريافت ميکنید:
(در مورد دو معناي /:دچار سردرگمي نشويد ،اين دو معنا ،نام ريشه بوده و در نامهاي
فايها نقش جداكننده دارد) .اغلب اينها فهرستها هستند ،اما یونيکس فايلي است كه
حاوي شكل قابل اجراء هستة اصلي یونيکس است .اطلعات بيشتر پيرامون اين موضوع
cat / usr/usr/you/junkرا انجام دهيد. در فصل 2آورده شده است .اكنون فرمان $
(اگر junkهنوز در فهرست شما وجود دارد).
24/322 محیط برنامه سازی لینوکس
نامت usr/you/junk/تحت تعنوانت ( path nameنام تمسير) فايل تنام تدارد Pathnam .داراي تمعناي
مستقيم است ،و نام كامل مسير را از ريشهت (در سرتاسر درخت دايركتوري) به فايل
خاص ،تنشان تميدهدت .اين تموضوع ،تقانون تكلي تدرت تسيستم تیونيکس تاست تكهت تشما
ميتوانيد تازت تنام تفايل تمعمولي تيا تاز تنام تمسير تاستفاده تكنيد .فايل تسيستم تشبيه تبه
شجرهت تنامت تشكل تگرفته تاست :درت تاينجات تتصويري توجود تدارد تكهت تاين تموضوع ترات تشفافتر
ميسازد.
Boot bin
فايل شما که junkنام دارد به فايل paulيا Maryمربوط نميباشد .نامهای مسیرها در صورتي موجود نميباشند که تمام فايلهای
موردتوجه در دايرکتوری شما باشند ،اما درصورتي که شما با دايرکتوری فرد ديگری يا با چندين طرح به صورت همزمان سروکار داشته
باشید ،به راستي آنها قابل استفاده مي شوند .برای مثال دوست شما ميتواند junkشما را با اظهار cat/usr/you/junk $چاپ کند ،به
طر مشابهي ،شما نیز ميتوانید با اظهار
$ 1S/usr/mary
data
junk
$
متوجهـ ـشويدـ ـکهـ Maryچهـ ـفايلهاييـ ـدارد،ـ ـياـ ـيكـ ـکپيـ ـازـ ـفايلهایـ ـاوـ ـراـ ـبرایـ ـخودـ ـتهیهـ ـکنید،ـ ـکهـ ـاينـ ـعملـ ـباـ ـفرمانـ $
cp/usr/mary/data dataانجام ميشود ،يا فايل او را ويراستاری کنید:
$ ed/usr/mary/dataدر صورتي که Maryنخواهد شما پیرامون فايلهايش جستجو کنید و يا برعکس ،محیط خصوصي ميتواند
در اين شرايط تنظیم شود .هر فايل و دايرکتوری اجازة اجراء خواندن ـ نوشتن برای مالك آن ،گروه و هر فرد ديگری را دارد که
ميتواند جهت کنترل دسترسي به آن ،مورد استفاده قرار گیرد 1( .ـ 1Sرا به خاطر آوريد ).در سیسمتهای محلي ما اغلب کاربران ،اغلب
اوقات از محیط باز نسبت به محیط خصوصي ،مزايای بیشتری دريافت ميکنند اما اين روش شايد در سیستم شما متفاوت باشد،
بنابراين راجع به اين موضوع در فصل 2مجدداً بحث خواهیمکرد .بهعنوان آخرين مجموعة تجربیات درمورد ناجهای مسیرها ،فرمان $
25/322 محیط برنامه سازی لینوکس
1S/bin/usr/binرا اجراء کنید .آيا برخي از نامها آشنا به نظر ميرسند؟ زماني که شما يك فرمان را به وسیله تايپ کردن نام آن پس از
آماده شدن ،اجراء ميکنید ،سیستم برای فايلي که به آن نام است به جستجو ميپردازد .به طور طبیعي اين فايل ابتدا در فهرست
(دايرکتوری) شما ظاهر ميشود( ،احتمال ً آن فايل را در کجا نميتوان يافت) ،بعد از دايرکتوری شما در bin/و نهايتا ً در usr/bin/
يافت ميشود .هیچ موضوع خاصي پیرامون فرامیني شبیه 1Sيا catوجود ندارد ،بر غیر از اينکه ،آنها در يك جفت دايرکتوری جمع
آوری شدهاند ،تا اينکه جهت فرايند جستجو و اجراء به آساني پیدا شوند .به منظور اثبات اين موضوع ،تلش کنید که برخي از اين
/ $ برنامهها را با استفاده از نامهای مسر کاملشان اجراء کنید:
bin/date
Mon sep 26 23 : 29 : 32 EDT 1983
bin/who / $
Srm tty/ sep 26 22:20
Crw ttJ4 sep 26 22:40
you tty5 sep 26 23:04
$
و هر آنچه را که به طور طبیعي پیش ميآيد را انجام دهید .اين اتفاقات ممکن است خارج از زمان کاری طبیعي ،سرگرم کنندهتر به نظر
برسد.
تغيير دادن دايركتوري ـ cd
درصورتي که شما بهصورت منظم با مری ( )Haryدر مورد اطلعات موجود در فهرستش در ارتباط باشید ،ميتوانید بگوئید «من
ميخواهم به جای کارکردن بر روی فايل خودم ،بر روی فايل مری کار کنم » .اين فرايند با تعويض فهرست خودتان بافرمان
cdامکانپذير استcd/usr/Mary $:
اکنون زمانیکه شما از يك نام نام (بدون ) ’/ Sبه عنوان شناسه برای برای catيا prاستفاده کنید ،اين عمل بر فايلي در فهرست ،Mary
دللت دارد .تغییر دايرکتوريها تحت تأثیر هیچگونه اجازة مربوط به فايلها نميباشد ،درصورتي که شما نتوانید به فايلي از دايرکتوری
خودتان دسترسي پیداکنید ،آن را به دايرکتوری ديگری که تغییر نخواهد کرد ،تغییر دهید .اين موضوع کامل ً مناسب است که فايلهای
شخصيتان را منظم کنید ،بنابراين تمام فايلهايي که به يك چیز مربوط ميشوند در يك دايرکتوری جداگانهای از ديگر موضوعات قرار
ميگیرد .برای مثال :درصورتیکه شما بخواهید کتابي بنويسید ،ممکن است بخواهید تمام متن را در يك دايرکتوری که کتاب نام دارد،
حفظ و نگهداری کنید .فرمان mkdirباعث بوجود آمدن دايرکتوری جديد ميشود.
mkdir book $ دايرکتوری جديد بساز
cd book $ رفتن به محل موردنظر
pwd $ از اينکه در محل صحیح قرار گرفتهايد اطمینان حاصل کنید.
26/322 محیط برنامه سازی لینوکس
usr/you/book/
… نوشتن کتاب موردنظر (پس از گذشتن چند دقیقه)
به میزان يك سطح بالرفتن (جابه جا شدن) در فايل سیستم
…$ cd
$ pwd
/usr/you
$
’ ‘ ..به منشاء همان دايرکتوری که شما معمولً در آن قرارداريد دللت ميکند و دايرکتوری يك سطح به ريشه نزديكتر ميشود ‘ 0 ’ .
مترادفي است برای دايرکتوری فعلي ،به دايرکتوری اصلي برميگردد.
cd $
تمام آنها به همراه خود دايرکتوری شما را به دايرکتوری اصلي برميگرداند ،يعني همان دايرکتوری که شما با آن مرتبط هستید .زمانیکه
کتاب شما چاپ شد ،ميتوانید آن فايلها را پاك کنید .به منظور پاك کردن دايرکتوری کتاب ،تمام فايلها موجود در آن را حذف کنید
rmdir book (روش سريعتر و کوتاهتر را به شما خواهیم آموخت) ،سپس فرمان cdرا در دايرکتوری اصلي کتاب اجراء کرده و $
را تايپ کنید rmdir ،تنها دايرکتوری خالي را حذف خواهد کرد.
اجازه دهید با الگوهای نام فايلها شروع کنیم .فرض کنید در حال تايپ کردن سند بزرگي همچون کتاب هستید .از لحاظ منطقي اين
سند بايد به قطعات بسیار کوچك مثل فصل و شايد بخش تقسیم شود .اساساً چنین تقسیمبندی بايد صورت گیرد ،اين فرايند به منظور
ويراستاری فايلهای بزرگ امری دشوار است .بنابراين ،بايد آن سند را به صورت تعداد فايلها تايپ کنید .ممکن است فايلها را برای هر
فصل جدا کنید و آنها را فصل ،1فصل 2و … نامگذاری کنید .يا در صورتیکه هر فصل به بخشهايي تقسیم شود ،ممکن است فايلهايي
ايجاد کنید که
فصل 2 .1 فصل 1 .1
فصل 2 .1 فصل 1 .2
……… فصل 1 .3
نام داشته باشد که اين عمل سازماندهي خاصي است که ما برای اين کتاب استفاده کردهايم .به کمك يك سیستم نامگذاری قراردادی
ميتوانید با يك نگاه اجمالي تعیین کنید که يك فايل خاص در کدام محل با کل فايلها تناسب پیدا ميکند .چه بخشهايي از کل کتاب را
ميخواهید چاپ کنید؟ در اين مورد ميتوانید بگوئید :
…… pr ch 1.1 ch 1.2 ch 1.3 $
اما به زودی از تايپ کردن نامهای فايلها خسته شده و شروع به غلط نوشتن ميکنید .اين جا همان مرحلهايي است که مختصر نويسي
نام فايلها وارد عمل ميشود .درصورتي که بگوئید *pr ch $
Shellعلمت * رابه معنای ‘هر رديفي از کاراکترها’ تلقي ميکند ،بنابراين *chالگويي است که تمام نامهای فايلها را که در دايرکتوری
فعلي همراه chهستند را هماهنگ ميکند Shell .لیستي فراهم ميآورد که به ترتیب الفايي است و لیست را به prانتقال ميدهد .فرمان
prهرگز علمت * را نميبیند ،الگوهايي که Shellرا هماهنگ کردهاند در دايرکتوری فعلي لیستي از رديفهای کاراکتری را بوجود
ميآورند که به prانتقال داده ميشود .مرحلة بحراني ،عبارتست از مرحلهايي که مختصر نويسي نام فايلها خصوصیت فرمان prنباشد،
اما کار برنامة Shellباشد .بنابراين ميتوانید از آن برای تولید توالي نامهای فايلها برای هر فرمان استفاده کنید .برای مثال ،برای شمردن
کلمات در اولین فصل:
$ wc *ch.1.
113 562 3200 chl.0
935 4081 22435 chl.1
974 4191 22756 chl.2
378 1561 8481 chl.3
1293 5298 28841 chl.4
33 194 2030 chl.5
75 323 2030 chl.6
)88933 16210 کل) 3801 ToTal
برنامهای به نام echoوجود دارد که برای بررسي معنای کاراکترهای مختصرنويسي بسیار مفید است .همانطور که حدس ميزنیدecho ،
چیزی به غیر از انعکاس شناسههايش انجام نميدهد:
$ echo hello world
hello world
$
28/322 محیط برنامه سازی لینوکس
usr/mary/انجام ميدهد و usr/*/calendar/لیست نامهای فايلها تمام کاربران فايلهای calendarرا توسعه ميدهد.
درصورتي که بخواهید برای همیشه معنای خاص * ،؟ و غیره را استفاده نکنید ،در اين صورت کل شناسه را در علمت نقل قول ،
همانند
? 1S $
قراردهید .همچنین ميتوانید ،کاراکتر خاصي را با backslashدر تقدم قرار دهید
? \ 1s $
(به خاطر داشته باشید ،از آنجايي که؟ علمت از بین بردن سطر يا پاك کن نیست ،اين backslashبه وسیلة shellتعبیر و تفسیر
ميشود نه بوسیلة هسته اصلي « .) »kerndنقل قول به طور مفصل در فصل ،3بحث شده است.
تمرين 4ـ )1تفاوتهای موجود بین اين فرامین چیست؟
$ 1S junk $ echo junk
$ 1S / $ echo /
$ 1S $ echo
$ 1S * $ echo
* $ 1S * $ echo
اغلب فرمانهايي که ما تاکنون ديدهايم خروجي را در پايان بوجود ميآورند و برخي نیز مانند ويراستار ،ورودی آنها از پايانه نشأت گرفته
است .اين امر تقريبا ً کلي است که پايانه بتواند به وسیله فايل برای ورودی و خروجي به صورت دوتايي يا برای هکردام به صورت
1Sلیستي از نامهای فايلها بر روی پايانة شما ايجاد ميکند .اما درصورتي که بگوئید $ مجزا جايگزين شود .به عنوان مثال:
$ 1S > file list
چنین لیست يکساني از نامهای فايلها در عوض در فايل ، filelistقرار خواهد گرفت .علمت < به معنای اين است که:
«خروجي را در فايل بعدی قرار دهید به جای اينکه در پايانه قرار دهید»
فايل درصورتي ايجاد خواهد شد که پیش از اين وجود نداشته باشد يا محتواهای قبل درصورتي که آن فايل وجود داشته باشد ،روی
هم نوشته شده باشد.
هيچ چيزي بر روي پايانة شما ايجاد نميشود .به عنوان مثال ديگر ،ميتوانيد چندين فايل
را در يك فايل به وسيله اشغال (ذخيره سازي) خروجي catدر يك فايل تركيب كنيد:
cat f1 f2 f3 > temp $
علمت << بیشتر کاری شبیه < را انجام ميدهد ،به غیر از اين مورد اين علمت به معنای «افزودن به قسمت انتهای فايل» نیز ميباشد.
يعني:
$ cat f1f2f3 >> temp
محتواي f1 f2 f3را در پايان هرآنچه كه از قبل در Tempوجود داشته ،به جاي نوشتن بر روي
محتواهاي موجود ،كپي ميكند .در موردت < (درصورتي كهت Tempوجود نداشته باشد) در
ابتدا باعث بوجود آوردن يك فايل خالي براي شما مي شود .به روشي مشابه ،علمت >
به معناي گرفتن ورودي از پايانه گرفته شود.
30/322 محیط برنامه سازی لینوکس
بنابراين ،ميتوانید نامهای را در فايل letآماده کرده و سپس آن را به وسیله mail mary joe Tom bob<leT $به چندين نفر
بفرستید .در تمام اين مثالها ،جاهای خالي در هر طرف از < >orاختیاری ميباشد ،اما قالب بندی ما ،قديمي است .با نشان دادن قابلیت
تغییر مسیر خروجي با < ،باعث ميشود که اين فرايند برای ترکیب فرمانهای به منظور تأثیر گذاری که به هیچ نحو ديگر امکان پذير
نیست ،ممکن و میسر شود .برای مثال ،به منظور چاپ فهرست الفبايي از کاربران،
$ who > temp
S sort < temp
از اين رو whoيك سطر از خروجي را در هر ارتباط کاربر چاپ ميکند و wc-1سطرها را ميشمارد (شمارش کلمات و کاراکترها را
متوقف سازيد) به اين ترتیب مي توانید کاربران را با
$ who > temp
$ wc – 1 < temp
شمارش کنید .ميتوانید فايلهای موجود در دايرکتوری فعلي را با
$ Is > temp
$ wc – 1 < temp
با اين وجود اين فايل شامل نام فايل tempاست که خودش هم در شمارش محسوب مي شود .ميتوانید نامهای فايلها را در ستونهای
درختي شکل با
$ IS > temp
$ pr – 3 < temp
چاپ کنید .و ميتوانید بینید که کاربر ويژهايي به وسیله ترکیب whoو grepارتباط برقرار کرده است
$ who > temp
$ grep mary < temp
در تمام اين مثالها ،کاراکترهای الگوی نام فايل مثل * ،اين نکته مهمي است که به خاطر آوريد ،تعبیر و تعريف علمت > و < به وسیله
shellصورت ميپذيرد نه به وسیله برنامههای خاص .تمرکز بخضي امکانات درـ shellبه اين معناست که تغییر جهت ورودی و
خروجي ميتواند با هر برنامه ای مورد استفاده قرار گیرد؛ خود برنامه متوجه نیست که اتفاقي در حال رخ دادن است.
اين امر باعث ميشود قانون مهمي مطرح شود .فرمان sort < temp $محتواهای فايل tempرا طبقهبندی ميکند ،همانگونه که $
sort tempاين کار را انجام ميدهد ،اما تفاوتي در اين فرايند وجود دارد .از آنجايي که رشته > tempبه وسیله shellتفسیر مي شود،
sortنام فايل tempرا به عنوان يك شناسنامه ،تشخیص نميدهد و آن در عوض ورودی استاندارد خودش را طبقهبندی ميکند ،به
نحوی که shellدارای برنامه تغییر مسیر است ،بنابراين اين فرايند نشأت گرفته از فايل است .آخرين نمونه نام tempرا به عنوان
شناسه به sortانتقال ميدهد که باعث خواندن فايل و طبقهبندی آن ميشود Sort .ميتواند فهرستي از نامهای فايلها را مثل sort $
temp1 temp2 temp3ارائه دهد اما ،اگر هیچ نام فايلي ارائه نشود ،اين برنامه وروديهای استاندارد خودش را طبقهبندی ميکند.
اين فرايند خصوصیت ضروری اغلب فرمانها است :در صورتي که هیچ نام فايلي مشخص نشود ،ورودی استاندارد ،پردازش ميشود.
اين امر به اين معناست که شما ميتوانید به سادگي برای اينکه متوجه شويد آنها چگونه کار ميکنند ،در فرمانها تايپ کنید .برای مثال
sort $
ghi
abc
CTL –d
Abc
31/322 محیط برنامه سازی لینوکس
Def
ghi
$
در بخش بعدی ،ما خواهیم ديد که اين اصل چگونه مورد استفاده قرار ميگیرد.
WCرا شرح دهید. Temp > Temp تمرين 6ـ ، 1خروجي از $
who > Tempچه اتفاقي ميافتد؟ درصورتي که نام فرمان را غلط نوشته باشید ،همانند $
تمام مثالها در پايان بخش قبلي بر روی يك راهکار تکیه دارد :خروجي يك برنامه را د ورودی برنامة ديگری از طريق يك فايل موقتي
قرار دهید .اما فايل موقتي هیچ هدف ديگری ندارد ،به راستي اين فايل به منظور مورد استفاده قرار گرفتن چنین فايلي نامناسب است.
اين نتیجه منجر به يکي از بخشهای اصلي سیستم يونیکس که همان لوله است ميشود .لوله روشي است برای اتصال خروجي يك
برنامه به ورودی برنامة ديگر بدون هیچ فايل موقتي؛ خط لوله عبارتست از اتصال دو يا تعداد بیشتر برنامه کاز طريق لولهها .اجازه دهید
برخي از مثالهای پیشین را به منظور استفاده از لولهها به جای فايلهای موقتي ،مورد بررسي مجدد قرار دهیم .کاراکترهای ستونهای
عمودی به Shellاعلم ميکند که خط لوله را تنظیم کند :
who : sert $ لیست فهرست بندی شده کاربران را چاپ کنید.
who : wc-1 $ کاربران را شمارش کنید
1S : wc-1 $ لیست 3ستوني از نامهای فايلها
who : grep mary $ به دنبال کاربر ويژه جستجوکردن
هر برنامهای که از پايانه خوانده شود ميتواند به جای آن از لوله نیز خوانده شود و هر برنامهای که در پايانه نوشته شود ميتواند در لوله
نیز نوشته شود .اين نقطه جايي است که قراردادن خوانده عبارتست از ورودی استاندارد ،البته زماني که هیچ فايل نامگذاری شده
سودمند نباشد.
هر برنامهای که بر اين قرارداد پیوندد ميتواند در خطوط لوله مورد استفاده قرار گیرد Grep، pr، sort .و wcهمگي از روشي استفاده
ميکنند که در خط لوله ذکر شده ميتوانید تعداد بسیاری از برنامههای موجود در خط لوله را داشته باشید:
$ |S : pr-3: | pr
اين فرمان لیست سه ستوني از نامهای فايلها بر روی مطر چاپگر ايجاد ميکند و
$ who : grep mary : we –1
تعداد دفعاتي که Maryارتباط برقرار کرده است را ميشمرد .برنامهها در خط لوله به همان تعداد ميرسند ،البته نه يکي پس از ديگری.
اين فرايند به اين معناست که برنامهها در خط لوله ميتوانند دوسويه عمل کنند ،هسته اصليـ ( )Kernelهرآنچه که برنامهريزی و
هماهنگ سازی به منظور آماده کردن آن برای انجام تمام کارها ،لزم دارند را مورد تعقیب قرار ميدهد .زمانیکه شما دچار حدس و
گمان شويد Shell ،کارها را هنگامي که شما درخواست لوله کنید ،تنظیم ميکند؛ برنامههای خاصي وجود دارند که از آن بياطلع بوده
و به منظور تغییر مسیر به کار ميروند .البته برنامه ها درصورتي که به اين ترتیب ترکیب شوند ،به صورت معقولنه عمل خواهند نمود.
اغلب فرمانها طرح معمولي و عادی را دنبال ميکنند ،بنابراين آنها به طرز مناسبي در خطوط لوله و در هر موقعیتي ،تطبیق مييابند .به
طور طبیعتي ،استمداد و کمك گرفتن از فرماني به اين صورت ميباشد:
32/322 محیط برنامه سازی لینوکس
Command optonal - arguments - Tianal - filenamesدرصورتي كه هيچ نام فايلي ارائه نشود،
فرمان ورودي استاندارد خودش را كه ناشي از نقص پايانه است (جهت آزمايش مناسب
است) را ميخواند اما ،اين موضوع ميتواند به منظور ناشي شدن از يك قايل يا لوله
تغيير جهت دهد .در همين زمان ،در قسمت خروجي ،اغلب فرمانها خروجيشان را بر روي
يك خروجي استاندارد ،مينويسند ،كه اين جريان همراه با نقصي به پايانه انتقال مييابد.
اما اين خروجي ميتواند در يك فايل يا لوله تغيير جهت پيدا كند .پيغامهاي خطا از ناحية
فرمانها به طر متفاوتي كنترل ميشود ،و يا ممكن است آنها در يك فايل را در قسمت
پايين لوله ناپديد شوند .بنابراين هر فرمان داراي يك خروجي خطاي استاندارد است كه به
طور طبيعي به سمت پايانه شما جهت گرفته است .يا به صورت تصويري عبارتست از:
Standard error
تقريباً تتمامت تفرمانهاييت تكهت تمات تتاكنونت تدرموردت تآنهات تصحبتت تكرديمت تبات تاينت تمدلت تسازگار
ميباشند؛ت تتنهات تاستثناءت تدرت تفرمانهاييت تهمچون ت dateو ت whoاستت تكهت تهيچت توروديت ترا
نميخوانند ،و به ميزان كمي شبيه cmpو ي diffاست كه دارد تعداد ثابتي از وروديهاي
فايل هستند( .اما به انتخاب ‘ ‘-در اين موارد توجه كنيد).
who / sort $ تمرين 7ت )1تفاوت بين
who > sort $
را توضيح دهيد.
پردازش
Shellعلوه بر تنظيم لولهها چند كارايي ديگر نيز دارد .اجازه دهيد به طور خلصه بيشتر به
جاي پرداختن به برنامهها به نوبت به اصول اجراي آنها بپردازيم ،چرا كه ما پيش از اين
33/322 محیط برنامه سازی لینوکس
تاحدودي به اين موضوع در ارتباط با لولهها پرداختيم براي مثال ،ميتوانيد دو برنامه را با
يك فرمان به وسيله جدا كردن فرمانها با استفاده ا نقطه ويرگول ) ؛ت ) اجراء كنيد،ت Shell
شما نيز ميتوانيد به صورت همزمان درصورت تمايل بيش از يك برنامه اجراء كنيد .براي
مثال :فرض كنيد مي خواهيد كار وقت گيري مثل شمردن لغات كتابتان را انجام دهيد ،اما
نميخواهيد كه صبر كنيد تا WCقبل از اينكه شما مشغول كار ديگري شويد ،تمام شود.
تحت عنوان process- idنام گرفت؛ ميتوانيد ا آن در فرمانهاي ديگري براي رجوع به برنامة
در حال اجراي خاص ديگري استفاده كنيد .اين نكتة مهمي است كه بين برنامهها و
پردازشها تمايز قائل شويم WC .يك برنامه است ،هر بار كه شما برنامة WCرا اجراء كنيد،
اين برنامه پردازش جديدي ايجاد ميكند .اگر چندين نمونه از برنامههاي يكسان در يك
زمانت تدرت تحالت تاجراءت تباشند،ت تهركدامت تبات process-idمتفاوتيت تبهت تصورتت تجداگانهت تپردازش
& pr ch* |pr ميشوند .درصورتي كه خط لوله با & شروع شود ،مثل $
precess-id of |pr /695
$
پردازش در آن ،در يك زمان شروع ميشود ت & در تمام خطوط لوله بكار برده ميشود .تنها
waitتا زماني صبر يك process-idپردازشهاي نهايي در تواليها ،چاپ ميشود .فرمان ت $
ميكند كه تمام پردازشهاي آغازشده با & پايان پذيرد .درصورتي كه اين پردازش سريعًا باز
نگردد ،به اين معناست كه شما هنوز فرمان در حال اجراء داريد .ميتوانيد فرمان waitرا با
deleteقطع كنيد .ميتوانيد ازت precess-idكه بوسيله shellچاپ ميشود براي متوقف كردن
فرايند پردازش آغاز شده با & ،استفاده كنيد:
kill 6944 $
درصورتيكهت تشمات process-idرات تفراموشت تكنيد،ت تميتوانيدت تازت تفرمانت psبرايت تاطلعت تيافتن
پيرامون هرآنچه كه شما در نظر داريد اجراء كنيد ،استفاده كنيد .اگر كار شما بينتيجه
بود kill O ،تمام پردازشهاي شما را به غير از ارتباط شما با shellرا از بين ميبرد .اگر شما
در مورد آنچه كه ديگر كاربران انجام ميدهند كنجكاو هستيد ps-ag ،به شما در مورد تمام
پردازشهايي كه در حال اجراء است اطلعاتي ميدهد .در اينجا نمونههايي از خروجيها
آورده شده است:
ps - ag $
PID Tty TIMe CMD
Co 6:29 /etc/Cron 36
5 6423
Sh - 0:02
Sh - 0:04 1 6704
35/322 محیط برنامه سازی لینوکس
عبارتست از پردازشگر زمان كه در دقايق و ثانيه ها به كار برده ميشود ،و مابقي فرماني
است كه بايد اجراء شود PS .يكي از آن فرمانهايي است كه در انواع متفاوت سيستمها ،
متفاوت است ،بنابراين خروجي شما ممكن نيست كه مانند اين مورد قالب بندي شود.
درصورتيكه شناسهها ممكن است متفاوت باشند (در اين مورد به صفحه فهرست (Ps )1
مراجعه كنيد ).پردازشها تداراي تيك نوع طبقه تبندي ساختار سلسله تمانند تهستند كه
فايلها نيز دارند .هر پردازش داراي مبداء بود و شايد داراي انشعاباتي نيز باشد .برنامة
Shellسيستم شما با پردازشي همراه با هر آنچه كه شما به خط پايانة سيستم متصل
كردهايد ،ايجاد ميشود .همان زماني كه شما فرمانها را اجراء ميكنيد ،آن پردازشها
انشعابات برنامة Shellسيستم شما را كنترل و هدايت ميكنند .در صورتيكه شما يكي از
برنامههايموجود تدرت تيكي تازت تآنت تپردازشها ترات تاجراءت تكنيد،ت تبراي تمثال تفرمانت 1بهت تمنظور
رهايي از ،ed
در اين صورت آن پردازش پردازش انشعاب متعلق به خودش كه انشعاب اصلي Shellاست
را ايجاد ميكند .بعضي اوقات پردازش تا زماني طول ميكشد كه شما بخواهيد اجراء
برنامهاي را شروع كنيد و سپس پايانه را خاموش كرده و بدون منتظر ماندن براي پايان
36/322 محیط برنامه سازی لینوکس
شما در نظر داشته باشيد كه ارتباط خود را قطع نمائيد ،ميتوانيد براي داشتن فرماني
كه كمي بيشتر طول بكشد ،از اين فرمان استفاده كنيد ،نهايتاً ،ميتوانيد به وضوح به
سيستم بگوئيد كه پردازش را زمان صبح يعني كه افراد طبيعتاً در خواب به سر ميبرند،
نه در محاسبه كردن ،شروع كند ،دين فرمان )at )1نام دارد.
at tme $
Whaterer commands
Jeu want
Cti-d
$
اين مورد كاربرد رايج است اما مسلمًا فرمانها ميتوانند از فايل نشأت بگيرند:
مناسب كردن محيط
37/322 محیط برنامه سازی لینوکس
يكي از مزاياي سيستم یونيکس اين است كه چندي روش براي نزديك كردن آن به علقه
شخصي شما يا قراردادهاي محيط محاسبة محلي شما ،دارد .براي مثال ما قبل از اين
مسئلة استانداردهاي متفاوت را براي پاك كن يا كاراكترهاي از بين برندة سطرها كه با
توت @ ،ذكر كرديم .شما ميتوانيد هر زمان كه خواستيد اين ¿ توجه به نقص عبارتند ازت
مورد را با فرمان
STTJ erase , Kill K $
عوض كنيد ( ،تغيير دهيد) .در اين فرمان eشامل هر كاراكتري است كه شما براي پاك كن
در نظر گرفتهايد و Kبراي كاراكتر از بين برندة سطرها در نظر گرفته شده است .اما تايپ
نمودن اين فرمان هر زمان كه با سيستم مرتبط هستيد ،دردسرساز است Shell .در اين
زمينه باعث رهايي از اين دردسر ميشود .اگر فايلي تحت عنوانت . profileدر دايركتوري
ارتباط شما وجود داشته باشد Shell ،قبل از چاپ اولين پيغام فرمانها را در آن ،هنگامي كه
شما ارتباط برقرار كردهايد ،اجراء ميكند .بنابراين ،شما ميتوانيد فرمانها را در . profileبه
منظور تنظيم محيط پيرامونتان به همان صورت كه دوست داريد ،قرار دهيد و آنها (فرمانها)
برگشت حروف به عقب ( )backspaceرا در . profileخود قرار دهيد STTy .نيز xرا براي xت CTL
ميفهمد ،بنابراين ،ميتوانيد همان اثر را با erase /h STTyدريافت كنيد .چرا كه cTL-hهمان
backspaceاست( .كاراكترت تبهت تعنوانت تيكت تهمت تمعني تقديميت تبرايت تاپراتورت تلولهت ت تاست،
بنابراين شما بايد از آن با علمت نقل قول محافظت كنيد) .درصورتيكه پايانة شما نقطة
Tabحساس نداشته باشد ،ميتوانيد Tabsت را به خط STTyاضافه كنيد:
STTy erase ∧ h - Tabs
اگر علقهمند هستيد كه بفهميد اشغال بودن سيستم هنگامي كه با آن مرتبط هستيد
چگونه تاست،ت who/wc - 1رات تاضافه تكنيد،ت تتات تاينكه تاينت تفرمان تتعداد تكاربران ترات تبشمارد.
درصورتيكه سرويس خبري وجود داشته باشد ،ميتوانيدت newsرا اضافه كنيد .بعضي از
38/322 محیط برنامه سازی لینوکس
11ت ايتتن عمل در Shellبه نحو بدي انجام ميگيرد .پس از اينكه هر فرمان به صورت به بار سيستم افزوده شد،
فايل را مورد بررسي قرار دهيد .همچنين ،درصورتيكه شما براي مدت طولني در حال كار كردن بر روي برنامه
ويراستاري باشيد اطلعاتي در مورد نامه جديد فرا نخواهيد گرفت چرا كه شما فرمانهاي جديد را با ارتباط
برقرارت كردن بات Shellاجراء نكردهايد .طرح و راهكار بهتر اين است كه هرچند دقيقه يكبار به جاي بعد از هر
فرمان ،اوضاع را مورد بررسي قرار دهيد .فصل 7و 5نشان ميدهد كه اين نوع از مرورگرهاي نامه چگونه عمل
ميكنند .سومين امكان كه براي هر فردي موجود نميباشد ،اين است كه تنها برنامة پست الكترونيكي خود
شما را مطلع بسازد :اين شرايط مطمئناً زماني ميسر ميشود كه نامه تنها براي شما فرستاده شده باشد.
39/322 محیط برنامه سازی لینوکس
سيستمتان اين عمل انجام ميگيرد .براي مثال :اين سطر مسير را به سمت يك مسير
استاندارد به علوة usr/games/تنظيم ميكند.
...PATH: :/ bin ;/usr/bin : /usr/ games one way
اين فرآيند كمي عجيب به نظر ميرسد :توالي نام دايركتوريها به وسيله :از يكديگر جدا
ميشوند .به خاطر داشته باشيد كه ‘ ’.همان دايركتوري فعلي است .شما ميتوانيد ‘ ’.را
حذف كنيد و جزء صفر درت PATHبه معناي دايركتوري فعلي است .راه ديگر براي تنظيم
مسير ( )PATHدر اين موردخاص عبارتستاز افزايش دادن معيار قبلي(PATH= $ PATH: /usr
) /games Anether wayميتوانيد مقدار هرگونه متغيرهاي Shellرا به وسيله پيشونددار كردن
نام آن با ، $بدست آوريد .در مثال بال ،حالت PAHT $مقادير فعلي را اصلح ميكند ،به
نحويت تكهت تبخشت تجديد،ت تافزودهت تميشودت توت تنتايجت تبه ت PATHبرگرداندهت تميشود .شما
ميتوانيد اين فرايند را با echoاثبات كنيد:
echo PATH is $ PATH $
PATH is :/bin:/usr/bini /usr/games
echo $ HOME $
usr/you your legin directory/
$
اگر شما برخي از فرمانهاي مربوط به خودتان را در اختيار داشته باشيد ،ممكن است
بخواهيد آنها را در دايركتوري مربوط به خودتان جمعآوري كرده و آنها را به مسير جستجو
شخصيتان اضافه نمائيد .در اين صورت PATH ،شما ممكن است چنين به نظر برسد:
PATH= : $ HOME /bin:/bin:/usr/bin:/usr/games
ما در مورد نوشتن فرمانهاي شخصيتان در فصل 3خواهيم كرد .متغير ديگر كه غالباً به
وسيله تزئينات ويراستاري متن استفاده ميشود تا به وسيله ، edعبارتست از TERMكه
نام نوعي از پايانههايي است كه شما از آن استفاده ميكنيد .چنين اطلعاتي ممكن
استت تاينت تامكانت ترات تبرايت تبرنامهت تهات تفراهمت تآوردت تكهت تصفحهت تنمايشت تشمات ترات تبهت تميزان
كارآمدتري كنترل تكند .بنابراين ممكن است چيزي شبيه تبهت TERM = a dm3رات به فايل
profileخودت تاضافهت تنمائيد .همچنينت تاينت تامكانت توجودت تداردت تكهت تازت تمتغيرهات تبرايت تاختصار
نويسي استفاده شود .اگر مكررًا به برخي از دايركتوريها با نامهاي طولني مراجعه داشته
40/322 محیط برنامه سازی لینوکس
5ت 1مابقي اطلاعات سيستم یونيکس
نکات بیشتری در مورد سیستم يونیکس در مقايسه با آنچه که ما در اين فصل ارائه کرديم وجود دارد ،اما اطلعات بیشتر در اين کل اين
کتاب مطرح شده است .اکنون ،بايد در مورد اين سیستم احساس راحتي کرده باشید به ويژه در مورد کتاب راهنما .زمانیکه شما سوالت
خاصي در مورد زمان و چگونگي استفادة فرمانها داريد ،کتاب راهنما جايگاه بررسي پاسخ شماست .همچنین اين نکته مفید و باارزشي
است که که گاهي در کتاب راهنما جستجو صورت گیرد ،به اين منظور که دانش شما از آشنايي با فرمانها و کشف اطلعات جديد ،به
روز شود .کتاب راهنما بسیاری از برنامههايي که ما نبايد توضیح دهیم و عبارتند از گردآورندگاني برای زبانهايي همچون FORTRAN
، 71برنامه های ماشین حساب همچون )bc)1( ، cu)1و )uncp)1برای ارتباطات بین ماشیني ،بستهبنديهای طرحها ،برنامههای آماری
و رمزهايي همچون ، )units)1را تشريح ميکند .همانگونه که پیش از اين نیز گفته شد اين کتاب جايگزين برای راهنما نميباشد بلکه
آن را تکمیل ميکند .در فصلهايي که در پیش است ،ما به بخشها و برنامههای سیستم يونیکس اشاره خواهیم کرد که اين فرايند از
اطلعاتي در راهنما آغاز ميشود اما رشتههايي را پي گیری ميکند که پیوند دهندة اجزاء و بخشهای کتاب است .اگرچه ارتباطات
برنامهها هرگز در کتاب راهنما به وضوح مشخص نشده است اما آنها اصل محیط برنامه سازی يونیکس را تشکیل ميدهند.
41/322 محیط برنامه سازی لینوکس
مقالة اصلي يونیکس توسطـ K.L.thompson , D.M.Ritchieتهیه شده است .اصل سیستم اشتراك زماني يونیکس تحت عنوان
ارتباطاتـ ACMدر جولی سالـ 1974تهیه شد و درـ CACMو در ماه ژانويهـ 1983دوباره چاپ شد( .صفحهـ 89چاپ جديد
موضوع بحث ماه مارس سال 1983قرار گرفت) .اين بررسي کلي از سیستم برای افراد علقه مند به سیستم عامل جهت خواندن توسط
هر فردی که برنامه نويس است ،ارزشمند است .مجله تکنیکي سیستم )Bell )BSTJکه موضوع ويژهای پیرامون سیستم يونیکس است
(جولی )1978حاوی مقالت بسیاری است که تشريح کنند تحول بعدی است و برخي از موضوعات گذشته شامل مقالت جديد
مجله CA CMاست که توسط Ritchieو thompsonتهیه شده است .دومین موضوع خاص RSTJحاوی مقالت جديد سیستم
يونیکس است که که به منظور چاپ شدن در سال 1984طرح ريزی شده است .محیط برنامة يونیکس که توسط J.R.Mashey ,
B.W.kernighanتنظیم شده (مجله کامپیوتر . IEEEماه آوريل سال )1981جهت انتقال خصوصیات اصلي سیستم به برنامه سازان
تلش ميکند .راهنمای برنامه ساز يونیکس در هر نوع برای سیستم شما ،فهرست فرمانها ،سیستم ها عادی و مشترك ،قالب بندی فايل
و روندهای حفظ و نگهداری مناسب هستند .شما بدون اين سیستم برای مدت طولن نميتوانید دوام بیاوريد اگرچه شما احتما ًل تنها به
خواندن بخشهای از جلد 1تا زمان شروع برنامهسازی نیازمند باشید .جلد 1چاپ هفتم کتاب راهنما توسط HolT ، Rinehartو
winstonبه چاپ رسید .جلد 2راهنمای برنامه ساز يونیکس تحت عنوان سندی برای استفاده از سیستم اشتراك زماني يونیکس نام
دارد و حاوی نکات آموزشي و مرجع برای اکثر فرمانها ميباشد .به ويژه اين کتاب نکات مقدماتي برنامهها و ابزارهای توسعه برنامهها
را به تفصیل بیان ميکند .ممکن است شما بخواهید اغلب اين مطالب را هرچند وقت مطالعه کنید .کتاب مقدماتي يونیکس که توسط
Aunو Nico Lomuto )1983ـ Hallـ )prenticeتهیه شده است ،مقدمة مناسبي برای افراد مبتندی بيتجربه به ويژه افرادی که
برنامه نويس نیستند ،به شمار ميرود.
42/322 محیط برنامه سازی لینوکس
مباني فايلها
يك فايل رشتهای از بايتها است( .بايت تکه کوچکي از اطلعات است ،که عموماً هشت بیت طول دارد .يك بايت را ميتوان معادل با
يك کاراکتر دانست ).سیستم هیچ ساختاری بر روی فايل و هیچ معنايي برای محتوای آن در نظر نميگیرد؛ مفهوم بايتها فقط به
برنامهايي که فايل را تفسیر ميکند ،بستگي دارد .علوه بر اين همانطور که خواهید ديد ،اين موضوع نه تنها در مورد فايلهای ذخیره
شده برروی ديسکت بلکه در مورد دستگاههای جانبي نیز صادق است .نوار مغناطیسي ،نامهها ،کاراکترهای تايپ شده روی صفحه کلید،
خروجي به چاپگر خطي ،دادههای جاری برروی خط لوله ،تا جايي که به سیستم و برنامههای داخل آن مربوط باشد همگي فايل و
معادل رشتهای از بايتها ميباشند.
بهترين راه درك فايل بازی کردن با آنها است ،بنابراين با ايجاد يك فايل کوچك شروع ميکنیم:
$ed
a
now is the time
for all good people
.
w junk
36
q
$ ls -l junk
-rw-rw-r-- 1 mahdi mahdi 36 Jul 4 11:21 junk
$
Junkفايلي 36بايتي است 36( .کاراکتری که شما هنگام ايجاد فايل تايپ کردهايد؛ البته به جز اصلحات اشتباهات تايپي ) .برای ديدن
فايل،
$ cat junk
now is the time
for all good people
$
43/322 محیط برنامه سازی لینوکس
دستور catنشان ميدهد که محتوای فايل چیست .دستور 2odتمام بايتهای فايل را بصورتي قابل رؤيت باز نمايي ميکند:
$ od -c junk
0000000 n o w i s t h e t i m e \n
0000020 f o r a l l g o o d p e o
0000040 p l e \n
0000044
$
گزينه cبه معنی تفسير(نمایش) بایتها به صورت کارکتری است .انتخاب گزينه ،bبايتها را
به اكتال ( )octalنيز نشان ميدهد:
od -cb junk $
0000000 n o w i s t h e t i m e \n
156 157 167 040 151 163 040 164 150 145 040 164 151 155 145 012
0000020 f o r a l l g o o d p e o
146 157 162 040 141 154 154 040 147 157 157 144 040 160 145 157
0000040 p l e \n
160 154 145 012
0000044
$
اعداد هفت رقمي که در پائین سمت چپ نمايش داده ميشوند ،شماره ترتیب کاراکتر در فايل برای اولین کارکتر نمايش داده شده در
آن خط است.
به هر ترتیب ،تأکید بر روی شمارههای اکتال ،يك نظريه پابرجا از PDP –11است ،که در آن اکتال نمادگذاری پیشنهادی بوده است.
مبنای 16سازگاری بیشتری با ساير سخت افزارها دارد؛ گزينه xبه odميگويد که اطلعات به صورت هگز چاپ کند.
توجه داشته باشید که در هر خط با يك کاراکتر 012اکتال پايان مييابد .اين کاراکتر ( newwlineخط جديد) اسکي است؛ چیزی که
سیستم در اثر فشار کلید enterدريافت ميکند .بنابر يك عرف وام گرفته شده از زبان Cکارکتر خط جديد با \nنمايش داده ميشود.
اما بايد توجه داشت که اين نوع نمايش قراردادی برای برنامههايي شبیه odاست تا راحتتر بتوان آن را خواند؛ در سیستم يك بايت با
مقدار 012ذخیره ميگردد.
کارکتر newlineرايجترين مثال كاراكترهای خاص است .سایر كاراكترها با بعضی از عمليات
كنترلی پايانه مرتبط ميباشند ،كه شامل ( backspaceپس برد به عقب) (با مقدار اكتال 010
،چاپ شده به صورت \ )bکارکتر )\tab)011،tو كاراكتر سر خط )\r ،015( 3ميباشد.
نکته بسیار مهم درك و تفکیك نحوه ذخیره سازی کارکترها در فايل و چگونگي تفسیر آنها در موقعیتهای مختلف است .برای مثال
وقتي شما backspaceرا روی صفحه کلید فشار ميدهید هسته آن را به معنای حذف کاراکتر قبلي تفسیر ميکند .کاراکتر قبلي و
backspaceناپديد ميشوند ،اما backspaceبه پايانه شما انعکاس داده ميشود تا مکان نما يك موقعیت به عقب برگردد.
اگر شما رشته ←\ را تايپ كنيد (\ و به دنبال آن یک )backspaceبه هر حال هسته تفسير
معمول خود از backspaceرا دارد؛ بنابراين ت \ حذف ميشود و بايت 010از فايل شما محو
ميشود .انعکاس backspaceبروي پايانه مكان نما را یک خانه به عقب برده و برروی \ قرار
میدهد.
چاپ فايلي که شامل backspaceاست؛ موجب ميشود که backspaceبدون تفسیر به ترمینال منعکس شود و در نتیجه مکان نما يك
octal dump2
Carriage return3
44/322 محیط برنامه سازی لینوکس
خانه به عقب برگردد .در صورت استفاده از odبرای نمايش فايلي که دارای backspaceاست ،اين کارکتر به صورت 010در صورت
استفاده از گزينه dو به صورت \bدر صورت استفاده از گزينه cنمايش داده خواهد شد.
داستان tabنیز به همین صورت است :در هنگام تايپ يك ،tabاين کارکتر به پايانه منعکس شده و همچنین به برنامهای که ورودی را
مخواند فرستاده ميشود .در خروجي tab ،به سادگي به پايانه فرستاده ميشود تا در آنجا تفسیر شود .البته در تفسیر tabبرای نمايش
تفاوتهايي وجود دارد .امکان تنظیم مشخصات سیستم برای نمايش اين کارکتر به صورتهای مختلف توسط هسته پیشبیني شده است.
بطور معمول هر کارکتر tabبا تعدادی فضای خالي جايگزين ميشود تا مکان نما به سر خانه جدولي بعدی برود .سر خانههای جدول
برروی ستونهای … ،25 ، 17 ، 9قرار دارند .دستور stty -tabsمنجر ميشود که از اين به بعد tabبا تعدادی فضای خالي جايگزين
شود .برای کسب اطلعات دقیقتر به راهنمای )stty)1مراجعه کنید.
رفتار enterقیاسي است .هسته enterرا به صورت يك کاراکتر سر خط و يك newlineمنعکس ميکند؛ اما تنها newlineرا در
ورودی ذخیره ميکند .برای خروجي نیز newlineبه آن دو کارکتر بسط داده ميشود.
روش يونیکس برای نمايش اطلعات کنترلي به خصوص در مورد کاربرد newlineبه منظور اعلم پايان خط متعارف نیست .در
بعضي از سیستمها به جای قراردادن هر رکرد در يك خط تعداد کارکترهای رکورد را نیز نگهداری ميکنند (البته بدون هیچ علمت پايان
خط يا رکوردی).
بقیه سیستمها پايان هر خط را با کاراکتر سر خط و newlineنمايش ميدهند؛ .زيرا اين کارکترها برای خیلي از پايانهها ضروری
است( .واژه linefeedمعادل اين دو کارکتر است که اين معادل غالبا « »CRLFخوانده ميشود که تقريباً قابل تلفظ است).
سیستم يونیکس هرگز دارای رکورد ،شمارنده رکورد و يا هر اطلعي که شما يا برنامه در فايل قرار نداده باشید ،نميباشد .يك
newlineزمان انعکاس به پايانه به کاراکتر سر خط و newlineبسط داده ميشود؛ اما برنامهها نیاز دارند که تنها با کاراکتر newline
سروکار داشته باشد زيرا اين همه چیزيست که آنها ميبیند .اين طرح ساده چیزی است که دقیقاً برای بسیاری از مقاصد خواسته شده
است .در صورت نیاز به ساختاری بسیار پیچیده ميتواند آن را برروی اين ايجاد کرد .انجام برعکس اين عمل ،ايجاد سادگي از
پیچیدگي ،سختر است.
تا زمانیکه انتهای خط با کاراکترـ newlineعلمتگذاری ميشود ممکن است انتظار داشته باشید که فايل به وسیله کاراکتر خاص
ديگری خاتمه پیدا کند .نماد ( )\eرا برای انتهای فايل در نظر بگیريد .در خروجي odکاراکتر خاصي در انتهای فايل نمايش داده
نميشود؛ بلکه تنها نمايش متوقف ميشود .بجای استفاده از کدی خاص ،سیستم با اعلم عدم وجود داده بیشتر در فايل خاتمه يافتن
فايل را مشخص ميکند .هسته طول فايل را نگهداری ميکند ،بنابراين برنامه پس از پردازش تمام بايتهای فايل با پايان فايل مواجه
ميشود.
برنامه با يك فراخواني سیستمي(روالي از هسته) که readنام دارد دادهّای درون فايل را بازيابي ميکند .هر بار که readفرا خوانده
ميشود ،بخش بعدی فايل مثل خط بعدی که روی پايانه تايپ شده است ،را بر ميگرداند .علوه بر اين readميگويد که چه تعداد
از بايتهای فايل برگردانده شده است .بنابراين انتهای فايل زمانیکه readتعدا بايتهای خوانده شده را صفر اعلم ميکند در نظر گرفته
ميشود .اگر مقداری بايت باقي مانده باشد read ،تعدادی از آنها را برميگرداند .واقعا اين احساس ايجاد ميشود که پايان فايل را با
يك مقدار خاص نبايد نمايش داد ،زيرا همانطور که قبل بیان شد مفهوم بايتها به نحوه تفسیر بايتها بستگي دارد .اما همه فايلها بايد
به پايان برسند و چون همه فايلها بايد به کمك readخوانده شوند ،برگشت صفر يك راه مستقل از تفسیر برای نمايش پايان فايل است
45/322 محیط برنامه سازی لینوکس
2.2.5, dynamically linked )uses shared libs(, stripped /usr/share/man/man1/ed.1.gz: gzip compressed
data, from Unix, max compression
$
اينها سه فايل نسبتا نوعي هستند که همه به ويراستار edمرتبطند :شاخهای که برنامه در آن موجود است ،باينری يا برنامه قابل اجرا و
صفحه راهنمای برنامه.
برای مشخص کردن نوع file ،توجهي به نام ندارد ،زيرا عرفه نامگذاری ،تنها يك قرارداد و کامل غیر حقیقي است .برای مثال پسوند .c
برای کدهای زبان Cدر نظر گرفته شده است ولي هیچ دلیلي وجود ندارد که شما از فايلي به نام a.cبا محتوايي دلخواه اجتناب کنید.
در عوض ،fileچند صد بايت اول فايل را ميخواند و به دنبال سر نخهايي برای تعیین نوع فايل ميگردد( .همانطور که قبل بیان کرديم
در بعضي مواقع مثل در مورد شاخهها fileميتواند از سیستم سئوال کند؛ البته حتي در همین موارد هم فايل با خواندن اول شاخه
ميتواند آن را تشخیص دهد).
بعضي مواقع سرنخها مشخصاند ،يك برنامه قابل اجرا توسط يك شماره جادويي در ابتدای خود علمتگذاری ميشود od .بدون هیچ
گزينهای فايل را به صورت 16بیتي يا 2بايتي نمايش داده و شماره جادوئي را قابل رويت ميکند:
$ od /bin/ed
0000000 042577 043114 000401 000001 000000 000000 000000 000000
0000020 000002 000003 000001 000000 107140 004004 000064 000000
0000040 127244 000000 000000 000000 000064 000040 000007 000050
عدد ،042577نشانگر وجود برنامهای قابل اجراست .يك کد اجرايي ممکن است توسط تعدادی پردازه همزمان اجرا شود .الگوی بیتي
که با 042577نشان داده ميشود ،يك متن ASCllنیست .و اين مقدار نميتواند توسط برنامهای شبیه ويراستار ساخته شود .اما شما
ميتوانید فايلي توسط برنامههای خاص خود بسازيد ،و سیستم فکر کند که آن يك برنامه اجرايي است.
برای فايلهای متني ،سرنخها ممکن است عمیقتر باشند .بنابراين fileبه دنبال واژهای شبیه #includeميگردد تا مشخص کند فايل
مورد نظر کد Cاست.
شما ممکن است از خود بپرسید که چرا سیستم نوع فايل را با دقت در نظر نميگیرد .برای مثال sortفايل bin/ed/را بعنوان ورودی
نگیرد .يکي از دليلش خودداری در جلوگیری از بعضي از محاسبات مفید است.
شاخهها و اسامي فايلها
همه فايلهای شما ،اسامي واضح و غیرمبهمي دارند که با home/you/شروع ميشوند .اما اگر junkتنها فايل شما باشد و lsرا اجرا
کنید به صورت usr / you / junk /تايپ نميشود .نام فايل بدون هیچ پیشوندی اينگونه تايپ مي گردد.
$ IS
junk
$
به همین دلیل برنامه در جريان که يك فرايند محسوب ميشود ،يك دايرکتری جاری دارد .و تمامي نام فايلها به صورت صنفي ايگونه
فرض ميشود که با نام آن ،دايرکتری آغاز شده است .مگر اينکه آنها مستقیماً با اسلش آغاز شوند .بنابراين راهيابي به سیستم عامل و IS
يك دايرکتری جاری دارد .فرمان « کارکرد دايرکتری را چاپ کن» دايرکتری جاری را شناسايي ميند.
$ pwd
/ usr / you
$
راهنمای جاری (دايرکتری جاری) مشخصهای از يك فرايند است نه از يك شخص يا برنامه .عموما ً همه دايرکتری ورود به سیستم
47/322 محیط برنامه سازی لینوکس
عامل را دارند و فرايندها دارای دايرکتری جاری هستند .اگر فرايند ،يك فرايند مولد ايجاد کند ،اين مولد ،دايرکتری جاری والد خود را
با تمامي مشخصاتش به دست ميآوردـ :البته اگر مولد يك راهنمای جديدـ (دايرکتری جديد) تغییر يافت تأثیر بر روی والد خود
نميگذارد .دايرکتری جاری به همان شکل باقي ميماند و به چگونگي مولد اهمیتي نميدهد.
تصويری از يك راهنمای جاری (دايرکتری جاری) مطمئناً يك نمادگزاری قرارداديست .زيرا ميتواند بسیاری از نوع سازیها را ذخیره
سازد .اما هدف واقعي و اصلي آن سازماني و از پیشبرنامه ريزی شده است .فايلهای مرتبط در دايرکتریهای يکسان ،به يکیگر تعلق
دارند usr / .معمول دايرکتری باليي از يك کاربر سیستم فايل است usr( .علمت اختصاری userاست) وقتي که شما وارد سیستم
عامل ميشويد usr / you /دايرکتری ورودی و دايرکتری جاری شما هستند:
usre / src /شامل منبعي از برنامههای سیستم است usr / src / smd / .شامل منبعي از فرمان يونیکس استusr / src / smd / sh / .
شامل فايل اصلي برای شل است و غیره .وقتي که شما دست به يك پروژه جديد ميزنید و يا وقتي يك سری فايل مرتبط داريد و يك
سری دستورالعمل بیان ميکنید ميتوانید با mkdirيك دايرکتری جديد بسازيد و آن را در فايلها قرار دهید.
$ pwd
/ usr / you
$ mk dir recipes
$ cd recifes
$ pwd
/ usr / you / recipes
$ mkdir pie cookie
$ ed pie / aplole
………
$ ed cookier / choc. Chip
………
$
توجه داشته باشید که رجوع کردن به يك دايرکتری فرعي بسیار ساده است pie/apple .يك مفهوم کامل واضحي دارد .دستورالعمل
apple pieدر دايرکتری بدين شکل است.
/ recipes / apple pie
اما قرار گرفتن تمامي piesبا هم سازمن يافتهتر به نظر ميرسد .برای مثال دستورالعمل crustبه جای کپي گرفتن از آن در هر سیستم
pieبه صورت recipes / pieاجرا شود.
گرچه سیستم فايل يك ابزار سازمان يافته قدرتمند است شما ممکن است فراموش کنید که فايل را کجا قرار دادهايد و يا به چه فايلي
دست يافتهايد .يك راه حل واضح و روشن برای يافتن فايل يك يا دو فرمان جستجو کردن در میان دايرکتریهاست .زمان ISبرای
يافتن فايل بسیار مؤثر است ،بدون اينکه به دايرکتری فرعي مراجعه شود.
$ cd
$ Is
junk
recipes
* $ file
jund ascit text
48/322 محیط برنامه سازی لینوکس
junk recipics
pie cookie
فرمان ( duکاربرد ديسك) نوشته شده است تا بیان کند چه مقدار از فضای ديسك توسط فايلهای داخل دايرکتری اشغال شده ،که
شامل تمامي فايلهای فرعي نیز ميباشد.
$ du – a
2 . / recipes / pie / apple
3 . / recipes / pie / crust
6 . / recipes / pie
3 . / recipes / cookie/ choc.chip
4 . / recipes / cookie
11 . / recipes /
1 . / junk
13 .
$
نام فايلها واضح و مشخص است .اين اعداد شماره بلوكهای ديسك ذخیرهسازی به ازای هر فايل محسوب ميگذارند ـ تقريباً به ازای
هر 1024يا 512بايت ـ اندازة هر دايرکتوری نشان ميدهد چند بلوك توسط فايلها در دايرکتری و دايرکتری فرعي اشغال شده که
شامل دايرکتری نیز ميشود Du .برای « »wllيك گزينه aدارد که باعث ميشود تمامي فايلها در دايرکتری چاپ شود .اگر يکي از
آنها دايرکتری du ،را اينگونه پردازش ميکند.
خروجي dw – aميتواند برای جستجوی فايلهای ويژه مسیری به طرف grepايجاد کند.
$ du – a / grep choc
$ . / recipes / cookie / choc. Chip
$
نگاهي دوباره به قسمت يك داشته باشید .نام (’ )‘.مدخل دايرکتری ميباشد که به خود دايرکتری رجوع پیدا ميکند ودستیابي به
49/322 محیط برنامه سازی لینوکس
دايرکتری را بدون دانستن نام آن مجاز مي شمرد Du .برای يافتن فايل به دايرکتری سری ميزند ،اگر شما به او نگوئید کدام دايرکتری
او فرض را بر اين علمت (’ )‘.ميگذارد .بنابراين junkو junk / .نام فايلهای مشابهند.
علوه بر مشخصات بنیادی داخل هسته ،دايرکتریها در سیستم فاعلي به عنوان فايل های معمولي قرار ميگیرند .آنها ميتوانند به
عنوان فايلهای معمولي نیز خوانده شوند .به منظور حفظ اعتدال و فايلهای کاربر ،هسته کنترل همه اطلعات دايرکتری را در دست
ميگیرد.
تايم نگاهي به بايتها در راهنما مياندازد :
به نام فايلهای پنهان شده در آنجا نگاهي کنید .فرمت دايرکتری مخلوطي از دودوئي و داده های در متن است .يك دايرکتری شامل
قسمتهای 16بايتي ميباشند و 14بايت آخر که نام فايلها را در بر دارند توسط ASCll Nul’sبسط داده ميشود( .که ارزش صفر
دارد) .و دو تای اولي بیان ميکند که سیستم اطلعات اداری را در کجای فايل قرار ميدهد .ما بعداً به اين مطلب دوباره اشاره خواهیم
‘ dot-dot”( ’. کرد .هر دايرکتری با دو ورودی آغاز ميشود (“‘.’)“dot”( and
دايرکتری ،ريشه ( )Rootسیستم عامل خوانده ميشود .هر فايلي در سیستم در دايرکتری ريشه و يا يکي از دايرکتریهای فرعي آن
است و ريشه ( ، )Rootدايرکتری والد آن است.
4ـ 2مجوزها
هر فايلي يك سری مجوزهايي مربوط به خود دارد که تعیین ميکند چه کسي چه کاری با فايل انجام ميدهد .شايد شما تصمیم داريد
نامههای عاشقانه خود را در سیستمي نگه داريد و با سلسله مراتبي در دايرکتری مرتب کنید .و نميخواهید ديگران آنها را بخوانند.
بنابراين شما ميتوانید مجوزهای آن نامهها را به طرحهای نامفهومي تغییر دهید .و يا ميتوانید مجوزها را به دايرکتریهايي که شامل
نامههاست تغییر دهید و بدين وسیله آنها را از دسترس ديگران دور کنید.
اما در اينجا هشدار ميدهیم که يك کاربر ويژه بر روی سیستم يونیکس قرار دارد که super-userخوانده ميشود .که ميتواند هر
فايلي را بر روی سیستم بخواند يا شناسايي کند Root .که نام ويژه وروديست مزيتهای super-userرا در بر دارد که با اداره کننده
سیستم در حین مراقبت از سیستم استفاده ميشود .اگر شما نام رم ز Rootرا بدانید .يك فرمان به نا م Suموقعیت shper-userرا
گزارش ميدهد .هر کس رمز super-userرا بداند ميتواند نامههای شما را بخواند .بنابراين موارد حساس را در اين فايل قرار ندهید.
اگر شما قصد پنهانکاری و اختفا داريد ميتوانید دادههای داخل فايل را تغییر داده تا super-userقادر به خواندن آن نباشد ( و يا
حداقل درك نکنند) .از فرمان cryptاستفاده کنید .البته cryptنیز نميتوند کامل امن و مطمئن باشد supper-hserميتواند فرمان
cryptرا نیز تغییر دهد و يك عملیات رمزنگاری بر روی الگوريتم cryptانجام دهد .روش اولي امکان خطا دارد بنابراين cryptدر
عمل نسبتا ايمن است.
در زندگي واقعي امنیت و اطمینان مستلزم رمزنگاری است تا لو داده نشود و به آساني نیز حدس زده نشود .گاهي اوقات سیستم اجرايي
خطاها برای کاربرهای خطاکار اين امکان را به وجود ميآورد تا مجوز super-userرا به دست آورد .نتیجه و کارايي اين امنیت در
متنهای ذکر شده در کتابشناسي انتهای اين فصل مورد بحث قرار ميگیرد.
وقتي که شما وارد سیستم عامل ميشويد اسمي را تايپ ميکنید و تأکید داريد که شما آن شخصي هستید اسم رمز را تايپ کردهايد .
اين اسم منطبق بر اسم ورودی شماست .ligin-id .البته سیستم شما را توسط شمارهها تشخیص ميدهد که user-idو يا uidخوانده
50/322 محیط برنامه سازی لینوکس
ميشود.
در حقیقت login-idمتفاوت ممکن است uidيکسان داشته باشد ،که آن را برای سیستم غیر قابل تشخیص ميسازد .البته اين عمل
نسبتا نادر ،به دليل امنیتي نامطلوب است .گذشته از ،uidشما يك هويت شناسي گروهي group-idترتیب ميدهید که شما را در رده
کاربرها قرار ميدهد .همه کاربرها بر روی بسیاری از سیستمها (بر خلف loging-idمثل )roatدر گروهي به نام otherقرار دارند.
ولي سیستم شما ممکن است متفاوت باشد .سیستم فايل و سیستم يونیکس به طور کلي تشخیص ميدهند که شما با مجوز داده شده با
uidو group-idچه ميتوانید بکنید.
فايل etc/passwd/يك سیستم رمزنگار است .و تمام ياطلعات ورودی را شامل ميشود .شما ميتونید uidو group-idرا توسط
يافتن نامتان در etc/passwd/پیدا کرده همانگونه که سیستم عمل ميکند.
$ grep you / etc / passwd
you : g k m b c T r j o A com : 604 .1 : y. O. A . people : / usr/ you
$
زمینهها و فیلدها در فايل رمزنگار توسط علمت « » :مجزا ميشوند و به صورت زيرطرحريزی ميشوند.
login-id : en crypted – passwd : uid : group – ld : miscell any
: login – directery : shell
فايلهای يك متن معمولي هستند و تفکیك ها و تعريفهای فیلد قراردادیاند که مطابقت ميکند با برنامههای که از اطلعات داخل
فايل استفاده ميکنند.
فیلد شل ،اغلب خالیست و مستلزم اينست که شما از شل پیش فرض به اين صورت استفاده کنید.
. bin / sh /فیلدهای متفرقه ممکن است هر چیزی را در بر داشته باشد و اغلب شامل اسم و آدرس و شماره تلفن شما ميباشد.
توجه داشته باشید اسم رمز شما بر روی فیلد دوم ظاهر ميشود ،البته تنها به صورت يك فرم رمزسازی شده .هر کسي ميتواند اسم
رمز را بخواند .بنابراين به کمك رمز هر کس ميتواند به جای شما از آن استفاده کند .وقتي شما اسم رمز را به loginميدهید او آن را
رمزسازی کرده و نتیجه را مقايسه ميکند با اسم رمز ،رمزسازی شده . etc/passwd/اگر آنها مطابقت کردند شما ميتوانید وارد
سیستم شويد .اين مکانیسم مؤثر است زيرا الگوريتم رمزسازی دارای يك ويژگیست که آن ورود از يك فرم خالي به يك فرم رمزسازی
شده به آساني صورت ميگیرد ولي معکوس اين عمل به سختي صورتپذير است .ممکن است به صورت g k m b c t r y o 4
رمزسازی شود ،اما بعد از دريافت نامه ،برگشتن به حالت اولیه آسان نیست.
هسته تشخیص ميدهد که به شما اجازه خواندن etc / passwd /داده شده البته توسط نگاه کردن به مجوزهای فايل .در اينجا برای هر
فايل سه نوع مجوز وجود دارد .بخوانید (متن را امتحان کنید) بنويسید (متن را تغییر دهید) و اجرا کنید (به عنوان يك بنا آن را اجرا
کنید ).به عله مجوزهای متفاوت توسط افراد متفاوت اجرا ميشود .به عنوان ماسك فايل شما يك سری مجوز خواندن ،نوشتن و اجرا
کردن داريد .گروه ( )groupشما يك دستگاه مجزا دارد ،هر شخص ديگری سه دستگاه دارد.
گزينه IS-1اطلعات مجوز را در میان ديگر چیزها چاپ ميکند.
اين دو خط ممکن است مجموع ًا اينگونه تفسیر شود login-id root :و group adm
etc / passwd /ميباشند که به طول 5115بايت است و در تاريخ 30آگوست و ساعت 10 : 45دقیقه صبح اصلح شده و دارای
يك پیوند است .اولین اسم در سیستم فايل ممکن است پیوند را در قسمت بعدی مورد بحث قرار دهد) بسیاری از طرحهای ISدر يك
سیستم ،مالك و گروه را به دست مي دهد.
خط – - - rw – r - - rنشان ميدهد که چگونه ISمجوزها را بر روی فايل نمايش مي دهد .ابتدا نشان ميدهد که اين يك فايل
معمولي است ،اگر يك دايرکتری وجود داشت ،علمت okدر آنجا وجود دارد .همه کارکتر ديگر بعدی يعني خواندن ،نوشتن و اجرا
کردن يك مجوز ،صاحب فايل را رمزگذاری ميکند( .بر مبنای uid( . rwيعني ( )rootمالك ميخواند و مينويسد اما فايل را اجرا
نميکدن يك فايل قابل اجرا به جای خط تیره xدارد.
سه کاراکتر بعدی ( ) - - rمجوزهای گروه را رمزگذاری ميکنند ،در اين حالت هر شخص در گروه و هر سیستم اداره کنندهای
ميتواند فايل را بخواند ولي نميتواند بنويسد يا اجرا کند .سهتای بعدی ( )- - also rمجوزها را برای بقیه کابرهای روی سیستم
تعريف ميکند ،در اين ماشین root ،اطلعات ورودی برای کاربر را تغییر ميدهد .اما هر کسي ميتواند فايل را برای يافتن اطلعات
بخواند .يك انتخاب به ظاهر درست برای گروه admميتواند نوشتن مجوزها روی
etc/passwd /باشد.
فايل etc / group /اسمهای گروه و group – idرا رمزگذاری ميکند .و مشخص ميکند کدام کاربر در کدام گروه است etc / / .
passwdتنها گروه ورودی را شناسايي ميکند .فرمان newgrpمجوزهای گروه را به گروه ديگری تغییر داده :
ed / etc / passwdو فايل passwdرا ويرايش کند .اما تنها rootميتواند معکوس تغییرها را هر کسي ميتواند بیان کند $ .
بنويسد.
ممکن است از خود بپرسید که چگونه اسم رمز را ميتوانید تغییر دهید در حالیکه اسم رمز فايل در حال ويراستن است .برنامهای که
اسم رمز را تغییر ميدهد passwdخوانده ميشود .که ممکن است شما آن را در /bin/پیدا کنید :
$ IS – 1 / bin / passwd
– rwsr–x r–x 1 root 8454 Jan 4 1983 / bin / passwd
$
توجه داشته باشید که etc / passwd /فايل متني است که شامل اطلعات وروديست .در حالیکه bin / passwd /در دايرکتر متفاوتي
فايلي است که شامل برنامههای قابل اجراست که به شما اجازه ميدهد اسم رمز اطلعات خود را تغییر دهید .مجوزها بیان ميکنند که
هر کسي ميتواند فرمان را اجرا کند اما تنها rootميتواند اسم رمز زمان را تغییر دهد S .که به جای Xدر فیلد اجرا برای فیلد ماسك
قرار ميگیرد بیان ميکند که وقتي فرمان اجرا ميشود .در حالت ، rootمجوزهايي که با مالك فايل همخواني داشته باشد به دست
ميآيند .
دستگاهـ uid-bitيك نظريه ساده اما ظريف است .که شمارش مشکلت ايمني را حل ميکند .برای مثال نويسنده برنامههای بازی
ميتواند برنامه set-uidرا برای صاحبش بسازد .بنابراين او ميتواند يك فايل خطي را که از دسترس ديگر کاربرها دور شده به روز
کند .اما مفهوم set-uidخطرناك است bin / passwd / .بايد درست و صحیح باشد .اما اگر درست نبود ميتواند اطلعات سیستم را
که تحت نظر rootاست را از بین ببرد .اگر او مجوز rw sr wx rwxرا داشته به وسیله هر کاربری که ميتواند فايل را به هر برنامهای
که هر کاری ميکند رونوشت شود .اين موضوع برایـ set-uidبسیار ضروری است .زيراـ rootبه مجوزهای هر سیستمي فايلي
52/322 محیط برنامه سازی لینوکس
دسترسي دارد .وقتي که فايلي تغییر ميکند ،سیستم , set – unix bitيونیکس را قطع ميکند تا خطر حوزه ايمني را کاهش دهد.
دستگاه uid bitقدرتمند است ،اما به طور ابتدائي برای تعداد معدودی سیستم برنامههايي نظیر passwdبه کار ميرود .بیائید به تعدادی
فايل معمولي نگاهي بیندازيم.
IS – 1 / bin / who $
rwxrwxv–w 1 root 6348 mar 29 1983 / bin / who -
whoچیزيست که توسط هر شخصي قابل اجراست و توسط rootقابل نوشتن است مصاحب گروهي مي باشد .منظور از قابل اجرا
بودن چیست وقتي که شما برای shellتايپ ميکنید :
who $
به نظرميرسد برای فايلهاييکه whoنامیده ميشود ،در يك سری دايرکتری ،يکي ازآنها bin /است .اگر او شبیه به يك فايل بود و
فايل نیز يك مجوز قابل اجرا داشت ،شل به هسته فرمان اجرا شدنش را ميدهد .هسته مجوزها را کنترل ميکدن و اگر معتبر بودند
برنامه را اجرا ميکند ـ توجه داشته باشید که يك برنامه تنها يك فايل است با مجوز قابل اجرا .در فصل بعدی ما به شما برنامههايي
نشان خواهیم داد که تنها يك فايل متني باشند و ميتوانند مانند فرمان اجرا شوند زيرا دارای دستگاه مجوز اجرا هستند.
مجوز دايرکتری مقداری متفاوت عمل ميکند ،اما مبنای نظريه يکي است.
$ IS - Id
d r w x r w x r 3 y-u 80 sep 27 06 : 11
$
گزينه IS-dبیشتر در مورد دايرکتری صحبت ميکنند تا در مورد اطلعاتش و منجر شدن dبه يك علمت خروجي .يك فیلد rيعني ،
شما ميتوانید دايرکتری را بخوانید .در نتیجه شما ميتوانید بفهمید که چه فايلي در ( ISو يا )odوجود دارد W .يعني شما ميتوانید
فايلها را در اين دايرکتری حذف يا اضافه کنید .زيرا او فايل دايرکتری را تغییر ميدهد و سپس مينويسد .در واقع شما نميتوانید به
راحتي روی يك دايرکتری بنويسد حتي اقدام rootبرای انجام اين کار ممنوع است.
$ who ’try to wer write ‘.
. : cannot creat you can’t
$
در عوض سیستمي وجود دارد که ميتواند فايلها را حذف و اضافه کند و تنها در حین آن ممکن است اطلعات دايرکتری را تغییر داد.
بیان ميکند که چه کسي ميتواند از روال سیستم برای تغییر و يا اصلح دايرکتری نظريه مجوزها اينگونه کاربرد دارد که فیلد w
استفاده کند.
اجازه حذف فايل به خود فايل بستگي ندارد .اگر شما مجوز را بر روی دايرکتری نوشتهايد ،ميتوانید همانجا فايل را حذف کنید ،حتي
اگر فايل در قبال نوشتن محافظت شده باشد .فرمان rmقبل از حذف کردن يك فايل حفاظت شده ،اجازه ميگیرد .به هر حال به منظور
اطمینان يافتن از اينکه شما واقعا ً ميخواهید حذف کنید ،در مواقع نادری برنامه يونیکس مقصود شما را دوباره کنترل ميکند( .علمت
Fبه روی rmباعث ميشود که حذف فايل بدون اجازه دوباره انجام پذيرد) فیلد Xدر مجوز برای يك دايرکتری به معني اجرا شدن
نميباشد .بلکه معني آن جستجو کردن است مجوز اجرا ،برای دايرکتری مشخص ميکند که آيا دايرکتری برای فايل جستجو شده
است .بنابراين ايجاد يك دايرکتری با وضعیت ( )X - -برای بقیه کاربرها امکان دارد .که اين مستلزم آن است که کاربرها به هر فايلي
که آنها در مورد دايرکتریاش ميدانند دسترسي داشته باشند .ولي ممکن است ISرا اجرا نکند و حتي آن را نخواند و نميداند که
فايل کجا قرار دارد .مجوز دايرکتری ( )- - rنیز همینگونه است .کاربر ميتواند ISرا ببیند اما نميتواند از محتوای دايرکتری استفاده
53/322 محیط برنامه سازی لینوکس
کند .بسیاری از تأسیسات از اين وسیله برای قطع کردن usr games /در طول ساعات شلوغ استفاده ميکنند.
فرمان ( chmodوضعیت متغیر) مجوزهای روی فايل را تغییر ميدهد.
$ chomed permissions filemond
نحو و دستور زبان مجوزها بد ترکیب و ناهنجار است .آنها ميتوانند به دو روش مشخص شوند .يکي به روش اعداد اکتال و يا با
توصیفات نمادی .اعداد اکتال برای استفاده آسانتر هستند .اما توصیفات نمادين بعضي وقتها مناسب تر است .زيرا آنها تغییرات مربوطه
را در مجوزها مشخص ميکنتد بهتر است شما بگوئید :
$ chomd rw – rw – rw – junk
تا اينکه بگوئید
$ chomd G G G junk
مدهای اکتال توسط بهم بستن با يکديگر مشخص ميشوند .عدد 4برای خواندن 2 ،برای نوشتن و 1برای اجرا کردن .اين سه رقم
مشخص ميکنند که ISمجوزی برای مالك ،گروه و هر شخص ديگريست .کدهای نمادی برای شرح و بسط دادن بسیار مشکل
هستند .شما برای دستیابي به توصیفات کاملتر ميتوانید به )chmod )1نگاه کنید .برای اهداف ،توجه داشته باشید که +يعني وصل
ـ يعني قطع کردن مجوز برای مثال … کردن مجوز
$ chmod + x commond
شخص را وارد کنید تا اين فرمان را اجرا کند.
$ chmod – w file
و سپس مجوز نوشتن را كه شامل مالك فايل است را قطع كنيد .به جز موارد عدم تعهد
در مورد super – userمالك فايل مجوز فايل را بدون توجه به مجوزها تغيير ميدهد .حتي اگر
شخص ديگري شما را وادار كند كه فايل را بنويسيد ،سيستم به شما اجازه نميدهد كه
بيتهاي مجوزش را تغيير دهيد.
$ IS – Id / user / mary
d r w x r w a r w x 5 mary 704 sep 25
$ chmod 444 / usr / mary
chmod : can’t change / usr / mary
$
اگر دايرکتری قابل نوشتن باشد ميتوانید فايل را بدون توجه به مجوز روی فايلها حذف کنید .اگر شما ميخواهید مطمئن شويد که
شما يا دوستتان فايل را هرگز از روی دايرکتری حذف نميکنید ،مجوز وشتن را از آن حذف کنید.
$ cd
$ date > temp
$ chmod – w.
$ Is – Id .
dr – xr – xr – x 3 you
rm : temp not removed
$ chmod 77 5
$ Is - Id
d r w x r w x r -x 3 you
$ rm temp
54/322 محیط برنامه سازی لینوکس
$
tempدر ايجا آمده شده است .توجه داشته باشید که تغییر دادن مجوز روی دايرکتری بر روی ديتهای متغیر تأثیری ندارد .ديتهای
متغیر بر روی تغییرات محتوای فايل مؤثر است ،و نه بر وضعیتش .مجوزها و ديتها بر روی خود فايل ذخیره نميشوند ،بلکه روی
ساختار سیستم که ثرة شاخص ( )index nodنامیده ميشود ذخیره ميشود.
5ت : inodes 2
هر فايلي دارای عناصر متعددی است .نام ومحتوا ،اطلعات اداره کننده مانند مجوزها و زمانهای اصلح اطلعات ذخیره کننده که در
inodeذخیره ميشود و با ضرورت دادههای سیستم سروکار دارد مانند :کجای ديسك محتوای فايل ذخیره شده و چقدر طولني
ميباشد و غیره ……
سه زمان در inodeوجود دارد .طول مدتي که محتوای فايل اصلح يافت و نوشته شد ،طول مدتي که فايل استفاده شد (خوانده شد يا
اجرا شد) و مدتي که inodeتغییر يافت .که در اين مورد ميتوان تشکیل مجوزها را مثال زد.
$ date.
The sep 27 12 : 07 : 24 EDT 1983
$ date > junk
- rw – rw – rw – 1 you
$ Is – Iw junk
- rw – rw – rw junk
$ Is – Ic junk
- rw – rw – rw - 7 you
$
تغییر محتوای فايل به زمان کاربرد آن تأثیری ندارد .همانگونه که گفته شد توسط Is-Iuو تغییر مجوزها تنها بر روی زمان تغییر inode
مؤثر است طبق گفتههای پیشین توسط . Is-Ic
$ chmod 444 junk
$ Is – Iu junk
- r - - r - - r - - 1 you 29 sep 27 06:11 junk
$ Is – Ic junk
- r - - r - - r - - 1 you 29 sep 27 12 : 11 junk
$ chmod 666 junk
$
گزينه ، Is-tکه فايلها را برطبق زمان ذخیره ميکند توسط پیشبیني مدت اصلح ،ميتواند ترکیبي از – Cيا – uباشد .که بیان
ميکند کدام inodesتغییر کرده و يا کدام فايل خوانده شده.
$ Is recipes
cookie
pie
$ Is – Iwt
total 2
d r w x r w x r w x 4 you
- rw – rw – rw – 1 you
$
recipesاخیرا خیلي استفاده شده بود .و ما نگاهي به محتوايش نیز انداختیم .درك کردن inodesبسیار مهم است ،نه تنها به خاطر
55/322 محیط برنامه سازی لینوکس
فهمیدن گزينه Isبلکه به خاطر اينکه در يك مفهوم قوی inoderيك فايل است .سلسله مراتب دايرکتری ـ نامهای مناسبي برای فايلها
فراهم ميسازد .نام داخلي هر سیستم برای هر فايل I-numberاست .شمارههای inodeاطلعات فايل را در بر دارد Is-1 .بیانگر I-
numberدر سیستمدهي (مبنا ده) است.
$ date > x
$ Is – i
1 5 7 6 8 junk
1 5 2 7 4 recipes
15852 x
$
دو بايت اول در ورودی دايرکتری تنها رابطه بین نام فايل و محتوايش ميباشد .نام فايلها در هر دايرکتری يك پیوند خوانده ميشود
زيرا او يك نام از سلسله مراتب دايرکتری را به inodeپیوند ميدهد i-number .يکسان ميتواند در بیش از يك دايرکتری ظاهر شود.
فرمان inode , rmرا حذف نميکند .او ورودی دايرکتری يا پیوندها را حذف ميکند .تنها وقتي آخرين پیوند با فايل ناپديد شود ،
سیستم inode ،را حذف ميکند .اگر i-numberدر يك ورودی سیستم صفر باشد ،به اين معني است که پیوند حذف شده است .نه
محتوای فايل .ممکن است پیوندهای ديگری نیز وجود داشته باشد .شما ميتوانید اثبات کنید که i-numberاز طريق حذف کردن ،به
طرف صفر ميرود.
فايل بعدی که در اين دايرکتری ساخته شده است ،به سوی يك شکاف بل استفاده پیش خواهد رفت .گرچه ممکن است i-number
متفاوتي داشته باشد.
Inold – file new file فرمان Inيك پیوند با فايل کنوني ميسازد$ .
هدف از پیوند ،دادن دو نام به يك فايل يکسان است .زيرا اغلب ميتواند به صورت دوايرکتری متفاوتي ظاهر شود .در بسیاری از
سیستمها پیوند با bin / ed called / bine / e /وجود دارد ،که ميتواند ويراستارها را eبخواند .دو پیوند با فايل به inodeمشابهي
اشاره دارد.
$ In junk likt ojunk
$ Is – Ii
total 3
1 5 7 6 8 - rw – rw – rw - 2 you
1 5 7 6 8 - rw – rw – rw - 2 you
1 5 2 7 4 d r w x r w x r w x 4 you
$
عدد صحیح چاپ شده بي نمجوزها و ماسكها عدد پیوند با فايل است .زيرا هر پیوندی به inodeاشاره دارد .همه پیوندها با طور
يکساني اهمیت دارند .هیچگونه تفاوتي میان اولین پیوند و پیوند بعدی وجود ندارد .توجه داشته باشید که مجموع فضای ديسك که با
Isمحاسبه شده اشتباه است زيرا دوبار حساب شده است.
وقتي که فايلي را تغییر ميدهید ،دستیابي به فايل ،تغییرها را آشکار ميسازد .البته تا زمانیکه پیوندها به فايل مشابهي اشاره داشته باشند.
$ echo x > junk
$ Is – I
total 3
- rw – rw – rw – 2 you
- rw – rw – rw – 2 you
d rw x rw x rx x 4 you
56/322 محیط برنامه سازی لینوکس
$
some old junkشبیه همان فايل junkقبلي است .به i-numberنگاه کنید تنها نامش تغییر يافته (ورودی دايرکتری با 8 7 5 1
inodeمرتبط است)
ما تمامي اين فايلها را که در يك دايرکتری به صورت به هم ريخته بود ،اجرا کرديم .اما آن تنها در راستای دايرکتری عمل ميکندIn .
برای برقراری ارتباط با نامهای يکسان در دايرکتریهای متعددی استفاده ميشود .مانند وقتي که افراد زيادی در يك برنامه شرکت
دارند mv .ميتاند فايل دايرکتری را به دايرکتي ديگری انتقال دهد .در حقیقت آنها اطلعات رايجي هستند که mvو cpدستور نحو
خاصي برای آنها دارند.
mv )or cp( file 1 file 2 … directory
فرمان بال يك يا دو فايل را به دايرکتری که در آخرين مرحله است حرکت ميدهد .کپيها و پیوندها با نام فايلهای مشابهي ساخته
ميشوند .برای مثال ،اگر ميخواهید ،مهارت خود را در ويراستاری امتحان کنید بايد با بیان اين فرمان آغاز کنید:
$ cp / usr / src / cmd / ed
اگر شما قصد داريد در يك شل کار کنید شماره فايلهای منابع متفاوت را اينگونه بیان کنید.
bin
در فصل اول نگاهي بر روی سلسله مراتب سیستم فايل انداختیم که از usr / you /شروع ميشود .اين بار قصد داريم در مورد آن با
يك روش برنامهريزی شده تحقیق و بررسي کنیم .که با بیش از سه ريشه ( )rootآغاز ميشود.
$ Is / boot
dev
etc
lib
tmp
unix
usr
$
/يونیکس برای خود هسته يونیکس يك برنامه است .وقتي سیستم شروع به کار ميکند unix /را از روی ديسك خوانده ميشود .اين
فرايند در دو مرحله رخ ميدهد .ابتدا فايل boot /خوانده ميشود ،سپس از روی unix/ميخواند .اطلعات زيادی در مورد اين فرايند
سیستم خود راهانداز ممکن است در )boot )8يافت شود .بقیه فايل در اسلش دايرکتری است که هر کدام قسمتهای کاملي هستند که
58/322 محیط برنامه سازی لینوکس
اگر سیستم شما ،خط ـ وصل منع کدرا داراست ،شما ميتوانید آن را در usr/src/پیدا کنید .صر وقت برای يافتن فايل جديد ارزش
زيادی دارد به خصوص در مورد usr /که چگونگي سازمان يافتن يك فايل و در کجا قرار داشتن آن را نشان ميدهد.
ما قبلً گذری بر dev /داشتهايم .همان طور که ميشود حدس زد dev /شامل فايل دستگاه است يکي از ظريفترين نظريات در مورد
سیستم يونیکس اين است که با دستگاه جانبي سروکار دارد .مانند ديسك ،دستگاههای نوار مغناطیسي ،چاپگر خطي ،پايانه و …
فايلي به نام dev / mto /وجود دارد که در داخل هسته ،چیزهايي که به اين فايل ارجاع داده ميشود به يك فرمان سخت افزاری
تبديل ميشود تا دستیابي به نوار مغناطیسي را ممکن سازد.
اگر برنامه بخواند dev / mto /اطلعات نوار مغناطیسي که به يك نوار ران نصب شده باز ميگردد.
$ cp / dev / mto junk
فرمان بال اطلعات نوار مغناطیسي را بر روی فايلي به نام junkکپي ميکند .در اينجا در مورد cpصحبتي نميکنیم .روی صحبتمان
تنها dev / mto /است .اين فايليست که دارای بايتهای همتراز است.
اولین چیزی که بايد بدان توجه داشت اينست که به جای شمارش بايتها يك جفت عدد صحیح وجود دارد و اينکه اولین کاراکترهای
مد همیشه bو يا cبوده .به اين صورت ISاطلعات را از يك inodeتايپ ميکند و دستگاه را از يك فايل عادی تغییر ميدهد.
Inodeهای يك فايل عادی شامل لیستي از بلوكهای ديسك است .که اطلعات فايل را ذخیره ميکند .برای دستگاه فايل inode ،به
جای اينکه شامل اسمهای داخلي برای دستگاه باشد و به جای يك جفت شماره ،به صورت مینو ر ( )minorو يا میژو ر ()major
خوانده ميشود .ديسك و نوار مغناطیسي ،دستگاههای بلوك هستند و هر چیز ديگری مثل پايانه و يا چاپگر و خط تلفن ،دستگاه
کارکتری هستند.
شماره میژور نوع دستگاه را کدگذاری ميکند ،در حالیکه شماره مینور /فواصل متفات دستگاه را تعیین ميکند .برای مثال dev / ttyo /
و dev / tty 1 /دارای دو دهانه در کنترلکننده پايانه است .بنابراين آنها دارای شماره میژور مساوی اما شماره مینور متفاوتي هستند.
نام فايلهای ديسك از دگرگوني سختافزاری گرفته شده است dev / rpo 0/ .و dev / rpo 1 /نام خود را از ديسكگردان D E C
RP06که وارد سیستم شده است ،گرفتهاند.
تنها يك نوار دگرگون وجود دارد که به طور منطقي به دو سیستم فايل تقسیم شده است .اگر نوار گردان دومي وجود داشت ،فايلهای
مرتبط خود را اينگونه نامگذاری ميکردند.
/ dev / rp 10 / dev / rp 11
اولین رقم ،فعالیت نوار گردان مشخص ميکند و دومین رقم بخشهای آن را.
ممکن است از خود بپرسید چرا به جای يك فايل دستگاه ديسك ،انواع متنعي از فايلهای دستگاه ديسك وجود دارد .به دليل تاريخي
و نگهداری آسان آن ،سیستم فايل به دو سیستم فرعي کوچك تبديل ميشود .فايلهای داخل سیستمهای فرعي به دايرکتری داخل
سیستم اصلي دسترسي دارد .برنامه etc / mount /بیان ميکند که فايل دستگاه و دايرکتری با هم ،همخواني دارند .
$ /etc/mount
rp 01 on /usr
$
60/322 محیط برنامه سازی لینوکس
در اين حالت سیستم root ، / dev / rp 00را اشغال ميکند (که اين توسط دايرکتریهای فرعييش ـ بر روی ، dev / rp 01قرار
ميگیرد.
سیستم فايل rootبايد به سیستم نشان داده شود ،تا اجرا شود dev / bin / .و etc /در سیستم rootادامه پیدا ميکند .و بسیاری از
سیستمهای bin / sh /بايد اجرا شود .در حین اين عملیات خود راهانداز ،همه سیستمهای فايلي چك ميشوند و به سیستم فايل
ميپیوندند اين عملیات پیوند ( mountingنصب کردن) نام دارد .يك نرم افزار با نصب يك بسته ديسك جديد بر ديسك ران برابری
ميکند که توسط super – userانجام ميگیرد بعد از اينکه dev / rp 01 /به عنوان usr /نصب شد ،فايل در سیستم فايل کاربر قابل
دسترسي است گويي که آنها جزئي از سیستم rootهستند.
يك مشکلي که وجود دارد اينست که شمارههای inodeدر سیستمهای فايلي متفاوت ،منحصربهفرد نیستند .هر سیستم فرعي دارای
سايزها و inodeهای مشخص و معیني است( .شماره بلوك قابل دسترسي در هر فايل) .اگر سیستم فرعي پر شود بزرگ کردن فايل در
سیستم فرعي غیرممکن است تا زمانیکه مکان جديدی احیا شود .فرمان ( dfمکان باز ديسك) فضای مناسبي را روی سیستم فايل نصب
شده درخواست ميکند.
$ df
/ dev / rp 0 0 1989
/ dev / rp 01 21257
usr ، 21257 /بلوك آزاد دارد .اينکه آيا اين يك فضای وسیع است يا نه به چگونگي استفاده از سیستم بستگي دارد .بعضي از اين
تأسیسات به فضای بیشتي در فايل نیاز دارند .فرمانـ dfتنوع وسیعي در فرمت خروجي دارد .خروجيـ dfشما ممکن است کمي
متفاوت به نظر برسد .وقتي که شما وارد سیستم عامل ميشويد يك خط پايانه و يك فايلـ dev /به دست ميآوريد که تمامي
کارکترهايي را که تايپ کرده و به دست آوردهايد را ارسال ميکند .فرمان ttyبیان ميکند که شما از کدام پايانه استفاده کردهايد .
$ who am 1
you tty 0 sep 28 01 : 02
$ tty
/ dev / ttyo
$ Is – 1 / dev / ttyo
crw - - w - - w – 1 you 1 , 12 sep 28 02 : 04 / deve / ttyo
$ date > / dev / ttyo
wed sep 28 02 : 40 : 51 Edt 1983
$
توجه داشته باشید که شما مالك دستگاه هستید و تنها شما اجازه خواندن آن را داريد به عبارت ديگر هیچ کس ديگری نميتواند به طور
مستقیم کارکترهايي را که تايپ کردهايد بخواند ولي ممکن است بتواند بر روی پايانه چیزی بنويسد .برای جلوگیری از اين عمل شما
ميتوانید از chmodو يا mesgاستفاده کنید.
$ mesg N
$ Is – 1 / dev / ttyo
crw - - - - - - - 1 you
$ mesg y
$
ميتوان توسط نام به پايانهای که از آن استفاده ميکنیم رجوع کرد .دستگاه dev / tty /مفهومي برای پايانه ورودی شما محسوب
ميشود و مي توان فهمید که از کدام پايانه استفاده ميکنیم .
61/322 محیط برنامه سازی لینوکس
اعداد در خروجي زمان ،سپری شدن زمان را نشان ميدهند و زمان cpuدر برنامه سپری ميشود و هنگامي که برنامه در جريان است
زمان cpuدر هسته سپری ميشود.
Egrepگونه قدرتمندی از grepميباشد که در بخش 4در موردش بحث خواهیم کرد و هنگام جستجوی يك فايل بزرگ سرعتش دو
برابر grepميشود .اگر فرم خروجي grepو egrepبه
dev / nu 11 /فرستاده نشد ما ميتوانیم منتظر صدها هزار کارکتری باشیم که ظاهر ميشوند روی پايانه قبل از يافتن اطلعات زمان.
62/322 محیط برنامه سازی لینوکس
در ادامه ،ما نیاز به اندکي درك بهتر در اين خصوص داريم که يك فرمان چیست و چگونه توسط مثل تفسیر ميشود .اين بخش يك
شمول رسميتر ،با اندکي اطلعات جديد از مبنای شل معرفي شده در فصل اول ميباشد.
ل نامیدن يك فايل برای اجرا ميباشد (بعداً ما انواع ديگری از فرمانها را خواهیم ديد) :
سادهترين فرمان ،تنها يك کلمه است که معمو ً
اجرای فايل /bin/Who
$who
You tty ۲ sep ۲۸ ۰۷:۵۱
$
يك فرمان معمولً با يك سطر جديد پايان ميپذيرد ،اما يك سمي کالن ؛ نیز يك پاياننمای فرمان ميباشد :
; $ date
web sep ۲۸ ۰۹:۰۷:۱۵ EDT ۱۹۸۳
teeاز ورودی خود برای فايل يا فايلهای نامگذاری شده و نیز برای خروجي خود کپي برميدارد ،در نتیجه wcهمان دادهها را دريافت
ميکند ،گويا اينکه teeدر خط لوله نميباشد.
پايان نمای ديگر فرمان ،آمپرساند $ميباشد .اين پاياننما ،دقیقاً شبیه سمي کالن يا سطر جديد ميباشد ،به جز اينکه اين علمت به شل
ميگويد که منتظر کامل شدن فرمان نباشد .اساسا ً $ ،برای اجرای يك فرمان طولني مدت « در زمینه » استفاده ميشود ،همچنانکه
64/322 محیط برنامه سازی لینوکس
$
با توجه به توانايي برای گروه بندی کردن فرمانها ،استفادههای جالب ديگری از پردازشهای زمینه وجود دارد .فرمان ، sleepچند ثانیه
مشخص قبل از خروج ،منتظر ميماند :
$ sleep 5
$ چنج ثانیه قبل از پیامواره طي ميشود
$ )sleep 5 ; date( $ date
5278
wed sep 28 09 : 18 : 20 EDT 1983 خروجي ا ز dateدوم
$ wed sep 28 09 : 18 : 25 EDT 1983 پیامواره ظاهر ميشود،سپس
ثانیه ،بعد ًا ميآيد date ۵
فرآيند زمینه آغاز ميشود ،اما سريعاً به خواب ميرود؛ در اين میان ،فرمان dateدوم ،زمان جاری و پیاموارههای شل را برای يك فرمان
جديد پرينت ميکند .پنج ثانیه بعد sleep ،خارج ميشود و اولین ، dateزمان جديد را پرينت ميکند .نشان دادن عبور زمان بر روی
کاغذ دشوار ميباشد ،در نتیجه شما بايد اين مثال را بررسي کنید( .بر اساس اينکه ماشین شما چگونه مشغول است و نیز بر اساس ساير
جزئیات ،تفاوت بین دو زمان ،ممکن است دقیقاً 5ثانیه نباشد).
اين يك روش آسان برای اجرای يك فرمان در آينده ميباشد؛ در نظر بگیريد
$ )sleep 300 ; echo Tea is ready( $ Tea will be ready in smunutes
5291
$
به عنوان يك مکانیسم باقیمانده قابل استفاده ميباشد ( .يك ctl-gدر رشته ،که پژواك شده باشد ،زنگ پايانه را به صدا در ميآورد
زماني که پرينت ميشود) .پرانتزها در اين مثالها لزم هستند ،چون حق تقدم $بیشتر از « ; » ميباشد.
پايان نمای $برای فرمانها بکار ميرود و چون خطوط لولهای فرمانها ،هستند در نتیجه شمانیاز به پرانتزها برای اجرای خطوط لولهای
در زمینه نداريد:
$ pr file | lpr $
برای پرينت فايل بر روی چاپگر سطری ترتیب داده ميشود بدون اينکه شما را برای خاتمه يافتن فرمان منتظر بگذارد .وارد پرانتز کردن
خط لولهای نیز دارای همین اثر ميباشد ،اما نیازمند تايپ بیشتر است :
($ )pr file | lpr $ همانند مثال قبل
اکثر برنامهها ،آرگومانها را روی سطر فرمان ميپذيرند ،مانند فايل (يك آرگومان برای )prدر مثال بال .آرگومانها ،کلمات هستند ،توسط
65/322 محیط برنامه سازی لینوکس
فاصلهها و جدول بنديها از هم جدا ميشوند ،و اساسا ً فايلهايي را که بايد توسط فرمان پردازش شوند ،نامگذاری ميکنند ،اما آنها
رشتههايي هستند که ميتوانند به هر روشي که برنامه متناسب به نظر ميرسد ،تفسیر شوند .برای مثال ،pr ،اسامي فايلها برای پرينت را
ميپذيرد ،پژواك آرگومانهای خود را بدون تفسیر پژواك ميکند و اولین آرگومانـ grepيك نمونه متن را برای جستجو مشخص
ميکند .و البته ،اکثر برنامهها نیز دارای انتخابهايي هستند که توسط آرگومانهايي نشان داده ميشوند که با علمت منها آغاز ميشوند.
کاراکترهای متعدد خاص که توسط شل تفسیر ميشوند مانند > ، | ، <،؛ و . $آرگومانهای برنامههايي نیستند که شل اجرا ميکند .در
عوض آنها ،کنترل ميکنند .که چگونه شل آنها را اجرا ميکند .برای مثال ،
$ echo hello > junk
به ما ميگويد که شل ،پژواك را تنها با آرگومان Helloاجرا ميکند و خروجي را در junkفايل قرار ميدهد ، String > junk .يك
آرگومان برای پژواك نميباشد ؛ بلکه توسط شل تفسیر ميشود و هرگز توسط پژواك مشاهده نميشود .در حقیقت ،اين عبارت نبايد
آخرين رشته درفرمان باشد :
$ > junk echo Hello
نیز شبیه به آن ميباشد اما کمتر بديهي است.
تمرين . ۳.۱تفاوتهای میان سه فرمان زير چه هستند؟
$ cat file | pr
$ pr < file
$ pr file
(در طي سالها اپراتور جهت دهي مجدد < ،تا حدودی زمینه خود را برای لولهها از دست داده است؛ به نظر ميرسد افراد طبیعتاً بیشتر
از « < »fileبه دنبال « » | cat fileميباشند).
۳.۲فرا كاراكترها
شل ،تعدادی ديگر از کاراکترهای خاص را تشخیص ميدهد؛ و عموميترين کاراکتر مورد استفاده ،کاراکتر ستاره * ميباشد که به شل
ميگويد که به جستجوی فهرست برای اسامي فايلهايي بپردازد که در آنها هر رشته از کاراکترها در موفقیت * رخ ميدهد .برای مثال،
*$ echo
يك پیام نمای ضعیف از lsميباشد .چیزی که ما را فصل اول ذکر نکرديم اين است که کاراکترهای تطبیق دهنده نام فايل ،به بررسي
اسامي فايلهايي که با يك نقطه شروع ميشوند نميپردازند ،و اين به خاطر اجتناب از مشکلت در خصوص اسامي « » .و « » ..
ميباشد که در هر فهرستي وجود دارند.
دستور اين است :کاراکترهای تطبیق دهندة اسم فايل فقط اسامي فايلهايي را تطبیق دهند که با يك دوره شروع ميشوند ،اگر دوره
آشکارا در نمونه ذخیره ميشود .به طور معمول ،يك echoيا دو echoدرست چیزی را که رخ ميدهد ،شرح ميدهند:
ls$
.Proflie
Junk
Temp
* $ echo
Junk Temp
* $ echo .
66/322 محیط برنامه سازی لینوکس
. .. .profile
$
کاراکترهای شبیه ستاره * که دارای ويژگیهای خاص ميباشند ،فراکاراکتر نامیده ميشوند .تعداد زيادی از آنها وجود دارد :جدول ۳.۱
يك فهرمست کامل است ،اگر چه تعداد کمي از آنها تا فصل ۵مورد بررسي قرار نميگیرند.
با توجه به تعداد فراکاراکترها ،راههايي برای جواب دادن به شکل وجود دارد « ،آن را تنها بگذاريد» ،بهترين و آسانترين راه برای
حمايت کاراکترهای خاص از تفسیر شدن ،ضمیمه کردن آنها در کاراکترهای نقل قولي منفرد ميباشد :
'***' $ echo
***
$
همچنین اين امکان وجود دارد که از نقل قولهای دو برابر « »...استفاده کنیم ،اما شل ،حقیقتاً درون اين نقل قولها را برای جستجوی ، $
« »...و \ ميخواند ،بنابراين « »...استفاده نميکند ،مگر اينکه شما قصد پردازش رشتة نقل قول شده را داشته باشید.
سومین راه ممکن ،قرار دادن يك پس کج خط \ در جلوی هر کاراکتری ميباشد که ميخواهید آن را از شل محافظت کنید ،مانند
*\*\*\ $ echo
اگر چه *\*\* ،خیلي انگلیسي نميباشد ،اما واژگان شل برای آن ،هنوز يك کلمه است که هر رشتة منفردی ميباشد که شل آن را به
عنوان يك واحد ميپذيرد ،همراه با فاصلهها ،البته اگر آنها نقل قول شوند.
نقل قولهای يك نوع ،از نقل قولهای نوع ديگر حمايت ميکنند:
''! $ echo '' Don’t do that
Don’t do that
$
$ echo X' * 'y
X*y
' $ echo '*' A' P
?* A
$
در مثال اخیر ،چون نقل قولها ،پس از اينکه کار خود را انجام دادند حذف ميشوند ،در نتیجه echoبه صورت يك آرگومان منفرد به
نظر ميرسد که فاقد نقل قول ميباشد.
رشتههای نقل قول شده ميتوانند شامل سطرهای جديد باشند :
$ echo ′ hello
> world ′
hello
world
$
رشتة « > » يك پیاموارة ثانويه چاپ شده توسط شل ميباشد .زماني که از شما انتظار ميرود که ورودی بیشتری را برای کامل کردن
يك فرمان تايپ کنید .در اين مثال :نقل قول روی اولین سطر بايد با نقل قول ديگر متوازن شود .رشته پیاموارة ثانويه در متغیر ps2
ذخیره ميشود و ميتواند بر طبق سلیقه تغییر داده شود.
$ echo x * y در همة اين مثالها ،نقل قول يك فرا کاراکتر ،مانع تلش شل برای تفسیر آن ميشود .فرمان
همه اسامي فايلهايي را که با xآغاز و با yپايان ميپذيرند ،پژواك ميکند .مثل همیشه ،پژواك چیزی در مورد فايلها يا فرا کاراکترهای
شل نميداند؛ تفسیر * ،اگر وجود داشته باشد ،توسل شل ذخیره ميشود.
چه اتفاقي ميافتد ،اگر هیچ فايلي با نمونه تطبیق داده نشود؟ شل به جای شکايت کردن (همچنانکه در نسخههای قبلي اين کار را انجام
68/322 محیط برنامه سازی لینوکس
داد) ،از رشته عبور ميکند ،گويا اينکه نقل قول شده است .معمول ً اين عقیده بدی است که به اين رفتار تکیه کنیم ،اما چنین رفتاری
ميتواند برای يادگیری وجود فايلهايي که يك طرح را تطبیق ميکنند ،استفاده شود :
$ ls x * y
يافت نمي شود x * y فايلهايي وجود ندارد :پیام از lS
$ > xyzzy وجود ميآيد xyzzy
$ ls x *y
xy zzy تطبیق ميشود فايل ، xyzzyبا x*y
$ ls ′x*y′ *، lsتفسیر نميکند
يافت نمي شود x * y
$
يك پس کج خط در پايان يك سطر ،باعث ميشود که سطر ادامه يابد؛ و اين يك روش برای نشان دادن يك سطر بسیار طولني در شل
ميباشد.
\ $ echo abc
\ > def
> ghi
abcdefghi
$
توجه داشته باشید که سطر جديد حذف ميشود ،زماني که قبل از پس کج خط ميآيد ،اما زماني که به صورت نقل قول ظاهر ميشود،
باقي ميماند.
فرا کاراکتر #تقريبا به صورت جهاني برای توضیحات شل استفاده ميشود؛ اگر يك کلمه شل با #آغاز شود ،ما بقي سطر ناديده گرفته
ميشود :
$ echo hello # there
hello
$ echo hello # there
hello # there
$
#بخشي از هفتمین ويرايش اصلي نبود ،اما عمیق ًا پذيرفته شده است و ما از آن در مابقي کتاب استفاده خواهیم کرد.
* $ ls .را شرح دهید. تمرين ۳.۲خروجي تهیه شده توسط
يونيكس و پژواك
يونیکس در سرزمین نیوجرسي ساکن بود ،يك خدمتکار زيبايي که دانشمندان از جاهای دور برای تعريف و تمجید از او مسافرت
ميکردند .همه مبهوت از عفت و پاکدامني او ،در صدد ازدواج با او بودند ،يکي به خاطر زيبايي دخترانة او ،ديگری برای فرهنگ آراسته
او ،اما فردی به خاطر زرنگي او درا جرای دقیق وظايفي که به ندرت انجام ميشد ،حتي در سرزمینهای ثروتمندتر .بنابراين قلب پر
احساس و خوش برخوردی يونیکس بود که همه خواستگاران غیرقابل تحمل خود را ميپذيرفت .به زودی بسیاری از فرزندان بزرگ
شدند و موفق شدند در تمام زمین پخش شدند.
طبیعت لبخند زد و مشتاق تر از ساير مخلوقات به يونیکس جواب داد .مخلوقات متواضعتر که اندکي از رفتارهای آراستهتر ميدانستند،
از پژواك او خوشحال ميشدند ،بنابراين آنقدر واضح و روشن بود که آنها معتقدند که او ميتواند از همان سنگها و چوبهايي پاسخ
بشنود که فريادهای آنها را در میان صحرا خراب و مخدوش ميکردند .و يونیکس مطیع ،مجبور به اجرای پژواکهای کامل از هر چیزی
بود که از او درخواست ميشد.
زماني که يك عاشق بي صبر از يونیکس درخواست ميکرد «چیزی را پژواك نکن» يونیکس از روی محبت دهانش را باز میکرد،
چیزی را پژواك نميکرد و دوباره دهانش را ميبست .جوانان به او ميگفتند؛ منظور شما چیست که دهانت را اينگونه باز ميکني؟ از
اين به بعد ،هرگز دهانت را باز نکن زماني که نميخواهي چیزی را پژواك کني! و يونیکس اطاعت کرد.
يك جوان حساس خواهش کرد؛ اما من يك عملکرد کامل ميخواهم ،حتي وقتي که شما چیزی را پژواك نميکني و پژواکهای کامل
نميتوانند از يك دهان بسته خارج شوند .يونیکس نميخواست حتي يك نفر را ناراحت کند و پذيرفت که چیزهای متفاوتي را برای
جوان بي صبر و جوان حساس بیان کند .او جوان حساس را با « »\ nفرا ميخواند.
زماني که او« » \nرا بیان ميکرد ،او حقیقتا ً چیزی نميگفت بنابراين بايد دهانش را دوبار باز ميکرد يك بار برای گفتن« »\ nو بار
ديگر برای گفتن هیچ چیزی ،و بنابراين او جوان حساس را راضي نکرد و جوان حساس بلفاصله گفت ،صداهای \nيك پژواك کامل
برای من هستند اما بار دوم آن را خراب ميکند .من از تو ميخواهم که يکي از آنها را انتخاب کني ،بنابراين يونیکس که نميتوانست با
ايجاد دردسر و مزاحمت زندگي کند ،موافقت کرد که برخي از پژواکها را از بین ببرد و آن را « » \ cبنامد .اکنون جوان حساس
ميتوانست با درخواست« » \cو « » \nبا هم ،يك پژواك کامل از چیزی داشته باشد .اما آنها میگويند که او به خاطر تعداد زياد
نمادگذاریها فوت کرد ،قبل از اينکه او حتي يکي از آنها را بشنود.
ل بسنجید.
تمرين .۳.۳پیشبیني کنید که کدام يك از فرمانهای grepزير انجام خواهند شد ،سپس درك خود را عم ً
فايلي که حاوی اين فرمانها باشد ،يك مورد آزمون خوبي ميباشد ،اگر شما بخواهید امتحان کنید.
تمرينـ . ۳.۴شما چگونه به grepميگويید که به جستجوی يك طرحي بپردازد که باـ « ــ » aآغاز ميشود؟ چرانقل قول کردن
71/322 محیط برنامه سازی لینوکس
آرگومان کمك نميکند؟ نکته :در مورد انتخاب Cـ تحقیق کنید.
تمرين ۳-۵توجه کنید به
*$ echo */
آيا اين فرمان همه اسامي را در همة جهتها تهیه ميکند؟ اسامي بر طبق چه نظمي آشکار ميشوند؟
تمرين ( ۳-۶پرسش راهکار) .شما چگونه يك /را در يك اسم فايل قرار ميدهید (يعني ،يك /که قطعات مسیر را جدا نميکند)؟
تمرين ۳-۷با فرمان
$ cat xy / y
و با فرمان
$ cat x >> x
چه اتفاقي رخ ميدهد؟
قبل از اينکه به بررسي آنها بپردازيد فکر کنید.
بنابراين شما نبايد هرزماني كه به سيستم وارد ميشويد ،آن را ريست سازي كنيد.
فرمانهاي ساده ديگري وجود دارند كه شما ميتوانيد به اين روش براي مناسب كردن
محيط خود بر طبق سليقه خود بوجود آوريد .برخي از فرمانهايي كه به نظر ما مناسب
ميباشند ،شامل موارد زير هستند:
Cs0كه توالي صحيح كاراكترهاي مرموز را براي پاك كردن نمايشگر روي پايانه شما پژواك
مي كند ( ۲۴سطر جديد يك اجراي كلي مطلوب ميباشد)؛
، What 0كه whoو ps - aرا براي بيان اينكه چه كسي به سيستم وارد ميشود و چه كاري
انجام ميدهد اجرا ميكند؛
Where 0كه شناسايي اسم سيستم يونيكسي را كه شما از آن استفاده ميكنيد پرينت
ميكند -اين فرمان قابل استفاده ميباشد اگر شما به طور منظم از آن استفاده كنيد( .
. ۳.۴پارامترها و آرگومانهاي فرمان
اگر چه nuهمانگونه كه هست ،مناسب ميباشد ،اما اكثر برنامههاي شل ،آرگومونها را
تفسير ميكنند ،در نتيجه براي مثال ،اسامي فايلها و انتخابها ميتوانند خاص باشند
زماني كه برنامه اجرا ميشود.
فرض كنيد ما ميخواهيم برنامهايرا بسازيم كه cxناميده ميشود براي اينكه حالت يك
فايل را براي قابل اجرا شدن تغيير دهيم ،بنابراين
cx nu $
يك صورت مختصر براي
chomd+xnu $
ميباشد ،ما به ميزان كافي براي انجام چنين چيزي اطلعات داريم .ما به يك فايل با نام
cxنياز داريم كه محتواي آن
Chomd + x filename
74/322 محیط برنامه سازی لینوکس
ميباشد .تنها مورد جديدي كه ما بايد بدانيم اين است كه چگونه بهت cxبگوييم كه نام
فايل چيست ،چون در هر زماني كه cxاجرا ميشود ،نام فايل متفاوت است.
زماني كه شل ،يك فايل از فرمانها را اجرا ميكند ،هر رخداد از ،1$توسط اولين آرگومان
جايگزين ميشود ،هر $2توسط دومين آرگومان جايگزين ميشود و به همين ترتيب تا $9
كه ما گفتيم
$ sh cx cx
دقیق ًا همانگونه که شل به طور خودکار انجام ميداد ،اگر cxقابل اجرا بوده و ما تايپ کرديم
$ cx cx
اگر شما بخواهید با بیش از يك آرگومان کار کنید ،چه بايد کرد؟ برای مثال ايجاد برنامهای مانند cxکه در يك زمان با چندين فايل کار
ميکند .اولین برش ناقص ،قراردادن ۹آرگومان در برنامه شل ميباشد ،مانند
Chomd+x$l $2 $3 $4 $5 $6 $7 $8 $9
( اين فرمان فقط تا $9کار ميکند ،چون رشته $10به صورت اولین آرگومان 1$و” 0تجزيه ميشود!) .اگر کار بر اين فايل شل ،کمتر
از نه آرگومان را فراهم کند ،تعداد آرگومانهای مفقوده ،رشتههای تهي هستند؛ تأثیر آن ،اين است که فقط آرگومانهايي که حقیقتا ً تهیه
75/322 محیط برنامه سازی لینوکس
شدهاند توسط زير شل از chomdعبور ميکنند .بنابراين اين اجرا کار ميکند ،اما به طور بديهي کثیف است و خراب ميشود ،اگر بیش
از نه آرگومان تهیه شود.
با پیشبیني اين برنامه ،يك صورت مختصر از * $را فراهم ميکند که به معنای «همه آرگومانها» ميباشد .روش صحیح برای تعريف
cxبه صورت * x chomd + $ميباشد که بدون توجه به اينکه چند تا آرگومان تهیه مي شوند ،کار ميکند.
با افزودن* $به مجموعة عملکردهای خود ،شما ميتوانید فايلهای شل مناسبي را تهیه کنید مانند 1cيا : m
$ cd/usr/you/bin
$ cat 1c
تعداد سطرها را در فايلها بشماريد 1 # c:
wc -1 * $
$ cat m
يك روش مختصر برای تايپ پست : #m
*mail $
$
هر دو ميتوانند به طور مناسب بدون آرگومانها استفاده شوند .اگر هیچ آرگوماني وجود نداشته باشد$ * ،تهيخواهد بود و اصل ً هیچ
آرگوماني از wcيا mailعبور نخواهد کرد .با وجود آرگومانها يا بدون آنها ،فرمان به طور صحیح راهاندازی ميشود:
* $ 1c / usr / you / bin /
usr / you /bin /cx 1
/ usr /you / bin /1c 2
usr / you / bin / m 2
/ usr / you / bin / nu1
2/ usr / you / bin / what
1 / usr / you / bin / where
9 total
$ 1s /usr/you/bin | 1c
4
$
اين فرمانها و سايرفرمانها موجود در اين فصل ،مثالهايي از برنامههای شخصي ،نوع چیزهايي که شما برای خود مينويسید و در bin
خود قرار ميدهید ،ميباشند ،اما بعید به نظر ميرسد که طورعمومي در دسترس باشند ،چون آنها بسیار وابسته به سلیقه شخصي
ميباشند .در فصل ،۵ما موضوعات مربوط به نوشتن برنامههای شل را که برای استفاده عمومي مناسب ميباشند ،مورد بحث قرار
ميدهیم.
آرگومانها برای يك فايل شل نبايد اسامي فايلها باشند .برای مثال ،جستجوی يك فهرست راهنمای تلفن شخصي را در نظر بگیريد .اگر
شما دارای فايلي باشید که به صورت / usr/you/bib/phone-bookنامگذاری شده باشد و شامل سطرهايي مانند زير باشد
در نتیجه فرمان grepميتواند برای جستجوی آن استفاده شود(.فهرست libشما يك مکان خوب برای ذخیره بانك اطلعاتي شخصي
ميباشد) .چون grepبه فرصت اطلعات اهمیتي نميدهد ،شما ميتواند به جستجوی اسامي ،آدرسها ،رمزهای پستي و يا هر چیزی
که دوست داريد ،بپردازيد .ميخواهیم يك برنامة فهرست مشارکت بسازيم و آن را به افتخار شماره مشارکت فهرست تلفن جايي که در
آن زندگي ميکنیم ۴۱۱بخوانیم:
411$ < ' echo 'grep $* /usr/you/lib/phone – book
411$ cx
joke 411 $
dial - a – jokeـ 976ـ 3838 212
Dial 411 $
ـ 3838 212 – 976 dial - a – joke
ـ 246ـ 4200 212 dial - a – prayer
ـ 976ـ 3636 212 dial santa
dow jones' 411' $
Grep : can't open jones در اينجا چیزی اشتباه است
نميتواند jonesرا باز کند
$
مثال آخر شامل نشان دادن يك مشکل پتانسیل ميباشد :اگر چه ،jones dowبرای ۴۱۱به عنوان يك آرگومان مفرد نشان داده ميشود،
اما شامل يك فضای خالي است و در نقل قولها بزرگتر نميباشد ،بنابراين زيرشل ،با تفسیر فرمان ، ۴۱۱آن را به دو آرگومان برای
grepتبديل ميکند :اين فرمان به گونهای است که شما تايپ کرديد
$ grep dow jones /usr/you/lib/phone – book
و چنین چیزی به طور بديهي اشتباه است.
يك راه علج ،اعتماد به روشي است که شل بر طبق آن ،نقل قولهای دوگانه را بررسي ميکند .اگر چه هر چیزی که با '…' نقل قول
ميشود ،تخطي ناپذير است ،اما شل به درون " …" برای \ 's ،s,$و "… " 'sنگاه ميکند .بنابراين اگر شما ۴۱۱را به صورت زير
تجديد نظر کنید
Grep "$*"/usr/you/lib/phone -book
• $توسط آرگونها جايگزين خواهد شد ،اما به عنوان يك آرگومان مفرد از grepعبور خواهد کرد ،حتي اگر دارای فاصلههای خالي
باشد.
dow jones 411 $
dow jones report 212-976-4141
به راستي ،شما مي توانید ( grepوبنابراين ) ۴۱۱را مستقل از مورد و با انتخاب y-بسازيد:
…$ grep - y pattern
با ، -yحروف موردی پايین در طرح نیز با حروف موردی باليي در ورودی ،متناسب خواهند بود( .اين انتخاب در هفتمین ويرايش
grepوجود دارد ،اما در سايرسیستمها وجود ندارد).
77/322 محیط برنامه سازی لینوکس
چهار نکته در مورد آرگومانهای فرمان وجود دارند که ما تا فصل ۵آنها را ناديده ميگیريم ،اما يکي از آنها ،چیز با ارزشي در اينجا
ميباشد .آرگومان ،$ 0نام برنامهای است که اجرا ميشود ـ در cx ،$0به صورت« » cxميباشد .يك استفاده جديد از $0در پیاده
سازی برنامههای ۲و ۳و ۴و … ميباشد که ورودی خود را در ستونهای زيادی پرينت ميکنندwho | 2 $ :
drh ttyo sep 28 21:23 cvw tty 5 28 21:09
dmr 4Tty sep 28 22:10 scj tty 7 28 22:11
You ttyg sep 28 23:00 J1b b tty 28 19:58
$
پیاده سازيهای 2و 3و … مشابهه هستند؛ و در حقیقت آنها مرتبط به همان فايل هستند:
انتخاب ،-tعنوان را در بالی صفحه خارج ميکند و انتخاب ،-1nطول صفحه را تا nسطر تعیین مي کند .نام برنامه ،تعداد ستونهای
آرگومان برای prميشود ،در نتیجه خروجي ،به صورت يك رديف در يك زمان در تعداد تعداد ستونهای مشخص شده توسط $0
پرينت مي شود.
اکنون ميخواهیم از آرگومانهای فرمان در يك فايل شل به تولید آرگومانها برگرديم .مطمئناً گسترش اسم فايل از فراکاراکترهايي شبیه *
عموميترين روش برای تولید آرگونها ميباشد( غیر از تهیه کردن آنها به صورت آشکارا) ،اما روش خوب ديگر از طريق اجرا کردن
برنامهميباشد .خروجي هر برنامه ،ميتواند با ضمیمه کردن تقاضا در نقل قولهای گذشته ' ، ' 1000در يك سطر فرمان قرار گیرد:
$ 'echo at the tone the time will be 'date
19830 EDT 02:15 : 00 29 At the tone the time will be thu sep
يك تغییر کوچك شرح ميدهد که ' ' 1000درون نقل قولهای دوگانه « … » تفسیر ميشود:
$ echo ''At the tone
$ ' the time will be 'date ''.
1983 EDT 03:07 : 00 29 The time will be thu sep
78/322 محیط برنامه سازی لینوکس
$
به عنوان مثالي ديگر ،فرض کنید شما ميخواهید پست الکترونیکي به يك لیست از افرادی بفرستید که اسامي loginآنها در فهرست
نامهرساني فايل وجود دارد .يك روش نامناسب برای انجام چنین کاری ،ويرايش فهرست نامه رساني در يك فرمان پستي مناسب و
نشان دادن آن به شل ميباشد ،اما بسیار راحتتر اين است که بگويیم.
$ mail 'cat mailing list' < letter
چنین فرمانيـ catرا برای تولید فهرستي از اسامي کاربرها اجرا ميکند و اين اسامي آرگومانهايي برای پست ميشوند( .زماني که
خروجي درنقل قولهای گذشته به صورت آرگومان تفسیر ميشود ،شل سطر جديد را به عنوا ن جداساهای کلمه و نه پايان نماهای سطر
فرمان ،بررسي ميکند؛ و اين موضوع به طور کامل در فصل ۵مورد بحث و بررسي قرار ميگیرد) .نقل قولهای گذشته به اندازه کافي
برای استفاده آسان ميباشند به گونه ای که حقیقتاً نیازی به يك انتخاب فهرست نامه رساني مجزا به فرمان پستي نميباشد.
يك روش اندکي متفاوت ،تبديل فهرست نامه رساني از يك فهرست از اسامي به برنامهای ميباشد که فهرست اسامي را پرينت ميکند:
نسخه جديد $ cat mailing list
echo don whr ejs mb
$ cx mailing list
$ mailing list
don whr ejs mb
$
اکنون به افرادی که درفهرست هستند نامه ارسال کنید
$ mail / 'mailing list' < letter
با افزودن يك برنامه ديگر ،حتي تغییرفهرست کاربر به صورت محاورهای امکانپذير ميباشد .برنامه pickنامیده ميشود:
…$ pick arguments
آرگومانها را در هر زمان يکييکي نشان ميدهد و پس از ارائه هر کدام منتظر جواب ميماند .خروجي ،pickآرگومانهايي ميباشد که
توسط پاسخهای ( yبرای «بله») انتخاب ميشوند؛ و هر پاسخ ديگری باعث ميشود که آرگومان حذف شود.
برای مثال،
$ pr 'pick*. C' | pr
هر اسم فايلي را نشان ميدهد که با ، Cپايان ميپذيرد؛ و اسامي که انتخاب ميشوند با prو 1prپرينت ميشوند ( pickبخشي از
هفتمین ويرايش نميباشد ،اما آنقدر آسان و مفید است که ما نسخههای مربوط به آن را در فصل ۵و ۶گنجاندهايم.
فرض کنید شما دومین نسخه از فهرست نامهرساني را داريد .سپس
۳.۶متغيرهاي شل
شل ،همانند اکثر زبانهای برنامهنويسي دارای متغیرهايي ميباشد که در زبان حرفهای شل ،گاهي اوقات پارامتر نامیده ميشوند.
رشتههايي مانند ،$1پارامترهای مکاني هستند -متغیرهايي که آرگومانها را برای يك فايل شل نگه ميدارند .رقم موقعیت را در سطر
فرمان نشان ميدهدـ .ماساير متغیرهای شل را نیز ديدهايم ، PATH :فهرست جهت ها برای جستجوی فرمانها ميباشد،ـ ،Home
فهرست loginشما ميباشد و به همین ترتیب تا آخر .بر خلف متغیرهای موجود در يك زبان منظم ،متغیرهای آرگومان نميتوانند
تغییر کنند؛ اگر چه PATHمتغیری است که ارزش آن $ PATHميباشد ،اما متغیر ۱که ارزش آن $1باشد وجود ندارد ،$1 .چیزی
بیشتر از يك نماد گذاری فشرده برای اولین آرگومان نميباشد.
با کنار گذاشتن پارامترهای مکاني ،متغیرهای شل ميتوانند بوجود آيند ،وارد شوند و تغییر کنند .برای مثال،
$ PATH = : /bin:/usr/bin
يك تخصیص ميباشد که مسیر جستجو را تغییر ميدهد .نبايد فضاهای خالي اطراف علمت مساوی وجود داشته باشد و ارزش
تخصیص يافته بايد يك کلمه مفرد باشد که به اين معنا است که بايد نقل قول شود اگر شامل فرا کاراکترهايي از شل ميباشد که نبايد
تفسیر شوند .ارزش يك متغیر با مقدم واقع شدن يك نام توسط علمت دلر بدست ميآيد :
$ PATH = $ PATH:/usr/games
$ echo $ PATH
:/usr/you/bin:/bin:/urs/bin/:usr/games
آن را مجدد ًا ذخیره کنید $ PATH=:/usr/you/bin:/bin/usr/bin
$
همه متغیرها برای شل خاص نیستند .شما ميتوانید متغیرهای جديد را با دادن ارزش به آنها ايجاد کنید؛ و به صورت سنتي ،متغیرها با
معني خاص در جعبه باليي تشکیل ميشوند و در نتیجه اسامي معمولي در جعبه پائیني قرار دارند .يکي از استفادههای عمومي از
متغیرها ،به خاطر آوردن رشتههای بلند مانند اسامي مسیرها ميباشد:
pwd $
usr/you/bin/
dir = pwd $ جايي را كه ما بوديم به خاطر آوريد
80/322 محیط برنامه سازی لینوکس
اين فرمان به اين معناست که فايل شل نميتواند ارزش يك متغیر را تغییر دهد ،چون فايل شل توسط يك زير شل اجرا ميشود:
"echo "X="GoodBye $ يك فايل دوسطری ايجاد کنید…
> echo $ X" > set X ......برای تعیین و پرينت X
cat setX $
"X="GoodBye
Echo $X
echo $ X $
81/322 محیط برنامه سازی لینوکس
فايل برای فرمان « » .با مکانیسم PATHجستجو ميشود ،در نتیجه مي تواند در فهرست binشما جايگزين شود.
زماني که يك فايل با « » .اجرا ميشود ،فقط به صورت ظاهری شبیه اجرای يك فايل شل مي باشد .فايل در مفهوم معمول کلمه اجرا
نمي شود .در عوض ،فرمانهای موجود در آن ،دقیقاًـ تفسیر ميشوند ،گويا اينکه شما آنها را به صورت محاورهای تايپ کردهايدـ -
ورودی استاندارد شل موقتاً برای خارج شدن از فايل تغییر مسیر ميدهد .چون فايل خوانده مي شود اما اجرا نميشود ،نبايد مجوزهای
اجرا داشته باشد .تفاوت ديگر اين است که فايل آرگومانهای سطر فرمان را دريافت نمي کند؛ در عوض $1 ،و $2و مابقي ،خالي
هستند .اگر آرگومانها عبور ميکردند خوب بود ،اما آنها عبور نميکنند.
روش ديگر برای تعیین ارزش يك متغیر در يك زير شل ،نسبت دادن آن به طور آشکارا به سطر فرمان ،قبل از خود فرمان مي باشد:
echo echo $ x’ > echo x $
CX echo x $
echo $ x $ همانند قبل
Hello
در زير شل تعیین نميشود x echox $
x = Hi echo x $ ارزش xاز زير شل عبور کرد
Hi
$
(در اصل ،نسبت دهيها در هر جايي از سطر فرمان وارد فرمان شدند و اما اين عبور با ( dd )۱تداخل پیدا کرد).
مکانیسم « » .بايد برای تغییر ارزش يك متغیر به طور دائم استفاده شود ،در حالیکه نسبت دهيهای خطي بايد برای تغییرات موقتي
استفاده شوند .به عنوان يك مثال ،دوباره جستجوی usr/games/را برای فرمانها با فهرستي که در PATHشما وجود ندارد ،در نظر
82/322 محیط برنامه سازی لینوکس
بگیريد:
$ /S / usr / games : grep fort
fortune فرمان بیسکويت شانسي
$ fortune
fortune : يافت نميشود
$ echo $ PATH
:/ usr / you / bin: / bin: / usr / bin usr/gamesدر PATHوجود ندارد .
$ PATH = /usr / games / fortune
.شمع را خاموش کنید ؛ کتاب را ببنديد ؛ زنگ را به صدا درآوريد
تغییر کرد .استفاده از gamesبه اين دو روش دشوار است ،اما منجر به يك مسیر ساده ميشود که برای استفاده ،مناسب و طبیعي است.
زماني که شما مي خواهید ارزش يك متغیر را در زير شلها ،قابل دستیابي کنید ،از فرمان exportشل بايد استفاده شود( .شما ممکن
است فکر کنید که چرا راهي برای صدور ارزش يك متغیر ازيك زيرشل به سقف آن وجود ندارد).
در اينجا يکي از مثالهای قبلي ما وجود دارد ،اکنون با متغیر صادر شده:
$ x = Hello
$ export x
$ sh شل جديد
$ echo $x xمعروف در زير شل
Hello
' $ x = 'Good Bye ارزش آن تغییر دهید
$ echo $ x
GoodBye
$ ctl – d از شل خارج شويد
$ به شل اولیه برگرديد
$ echo $ x
Hello x still Hello
$
expor tدارای معنای دقیقي ميباشد ،اماحداقل برای اهداف روزمره ،يك دستور ورق زدن ،کافي ميباشد ؛ مجموعه متغیرهای موقت
را برای راحتي کوتاه مدت صادر نکنید ،اما همیشه متغیرهايي را صادر کنید که ميخواهید در تمام شلها و زير شلهای خود ست
کنید( .برای مثال شامل شلهايي که با فرمان ! S’ edآغاز ميشوند).
بنابراين ،متغیرهايي که برای شل ،خاص ميباشند ،مانند PATHو ،HOMEبايد صادر شوند.
تمرين ۳.۱۳چرا ما همیشه فهرست جاری را در PATHقرارميدهیم؟ اين فهرست در چه جايي بايد قرار گیرد؟
آشنا شديم ،اغلب از فايلها و لولهها و يا به طرف فايلها و لولهها تغییر جهت ميدهند .خروجي با شمارة ، ۲يك خروجي خطای
استاندارد ميباشد و در حالت عادی راه خود را به سمت پايانة شما پیدا ميکند.
گاهي اوقات ،برنامهها ،خروجي را بر روی خطای استاندارد تولید ميکنند حتي زماني که آنها به درستي کار ميکنند .يك مثال عمومي،
زمان برنامه ميباشد که يك فرمان را اجرا ميکند و سپس به خطای استاندارد گزارش ميدهد که چقدر زمان ميگیرد.
$ time wc ch 1 . 3
22691 4288 931 ch 1 . 3
real 0/1
rse 4/0
sys 4/0
real 1/0
user 4/0
sys 0/3
$
ساخت ( filename >2هیچ فاصلهای بین 2و > نبايد باشد) خروجي خطای استاندارد را به درون فايل هدايت ميکند ؛ اين ساختار از
نظر نحوی نامناسب است اما کارش را انجام ميدهد( .زمانهای ايجادشده توسط timeبرای آزمايش کوچکي مانند اين نمونه صحیح
نمي باشند .اما يك توالي از آزمايشات بلندتر ،اعداد مفید و به طور معقول قابل اعتماد هستند و شما ممکن است به خوبي بتوانید آنها را
برای تحلیل بیشتر ذخیره کنید؛ برای مثال به جدل ۸.۱مراجعه کنید).
همچنین اين امکان وجود دارد که دو مسیل خروجي را در هم ادغام کنیم:
نمادگذاری 2 > $1به شل ميگويد که خطای استاندارد را بر روی همان مسیل خروجي استاندارد قرار دهد .ارزش قابل يادآوری برای
آمپرساند وجود ندارد ؛ شیوهای است که به سهولت بايد آموخته شود .شما نیزميتوانید از 1> $2برای افزودن خروجي استاندارد به
خطای استاندارد استفاده کنید:
Echo … 1 > $2
85/322 محیط برنامه سازی لینوکس
بر روی خطای استاندارد پرينت ميکند .در فايلهای شل ،اين فرمان از ناپديد شدن پیغامها درون يك لوله يا درون فايل به طور تصادفي
،جلوگیری ميکند.
شل مکانیسمي را بوجود مي آورد که بواسطه آن شما ميتوانید ورودی استاندارد را برای يك فرمان ،در طول دستور قرار دهید ،به جای
اينکه بر روی يك فايل جداگانه بگذاريد .در نتیجه فايل شل ميتواند به طور کامل همه چیز را در خود داشته باشد .برنامة اطلعات
فهرست ما ،۴۱۱ ،ميتواند به اين صورت نوشته شود:
$ cat 411
grep "$ *" << End
ـ 976ـ dial – a – joke 3838 -212
ـ 246ـ dial – a – prayer 4200 -212
ـ 976ـ dial santa 3636 212
ـ 976ـ dow jones report 4141-121
End
$
جارگن شل برای اين ساختار ،يك سند در اينجا ،ميباشد؛ به اين معنا که ورودی در اينجا صحیح است به جای اينکه دريك فايل در
جای ديگر باشد ، << .به ساختار ،علمت ميدهند؛ کلمهای که دنبال ميشود (کلمة Endدر مثال ما) ،برای مجزا ساختن ورودی
استفاده ميشود ،که به عنوان هر چیزی برای رخداد اين کلمه روی يك سطر توسط خودش ،پذيرفته ميشود .شل برای '…' ، $و ،1
دريك سند در اينجا ،جايگزين ميکند ،مگر اينکه بخشي از کلمه با نقل قولها يا يك پس کج خط ،نقل قول شود؛ در اين مورد ،کل
سند ،به صورت حرفي ميشود.
ما به موضوع اسناد در اينجا ،در پايان فصل ،با يك مثال جالب تر مراجعه ميکنیم.
جدول . ۳.۲جهت دهي های مجدد و متعدد ورودی ـ خروجي را که شل آنها را درك ميکند ،لیست ميکند.
تمرين . ۳.۱۴نسخة سند در اينجای ۴۱۱را با نسخة اصلي مقايسه کنید .کدام يك راحتتر قابل نگهداری است؟ کدام يك مبنای بهتری
برای يك سرويس کلي ميباشد؟
شل ،حقیقتا ً يك زبان برنامه نويسي ميباشد :شل دارای متغیرها ،حلقهها ،تصمیمگیری و مواردی از اين قبیل ميباشد .ما در اينجا به
بحث و بررسي درخصوص حلقه سازی اساسي ميپردازيم و درخصوص روند کنترل در فصل ۵صحبت ميکنیم.
حلقهای کردن يك مجموعه از اسامي فايلها ،بسیار عمومي است و بیان forشل ،تنها بیان روند کنترل شل ميباشد که عموما ً بايد در
پايانه تايپ شود به جای اينکه در يك فايل يا دراجرای بعدی قرار گیرد .نمو عبارت است از:
for var in listof wrds
do
commands
done
برای مثال ،يك بیان forبرای پژواك اسامي فايل ها در هر سطر به اين صورت است.
* $ for I in
> do
> echo $ i
> done
« »iميتواند هر متغیری از شل باشد ،اگرچه ، iقديمي است .توجه داشته باشید که ارزش متغیر ،توسط i$ارزيابي ميشود ،اما ارزش
حلقه ،به متغیربه صورت ، iنسبت داده ميشود .ما از * برای جمع کردن همة فايلها در فهرست جاری استفاد کرديم ،اما از هر فهرست
ديگری از آرگومانها ميتوان استفاده کرد .درحالت عادی ،شما ميخواهید چیزی جالبتر از صرفاً پرينت کردن اسامي فايلها انجام دهید.
چیزی که ما غالبا ً انجام ميدهیم ،مقايسه کردن يك مجموعه از فايلها با نسخههای قبلي ميباشد برای مثال ،برای مقايسة نسخة قبلي
فصل ( ۲حفظ شده در فهرست قبلي) با نسخة فعلي:
$ 1S ch2 . * | 5
ch1 . 2 ch2 . 2 ch3 . 2 ch4 . 2 ch5 . 2
ch6. 2 ch 7. 2
*$ for i in ch2.
> do
> echo $ i:
> diff – b old / $ i $ i
> echo يك سطر خالي برای قابلیت خواندن اضافه کنید
87/322 محیط برنامه سازی لینوکس
> do
> echo $i:
> diff old / $ i $i
> done | pr | lpr
chr. 1 ? y
؟ ch2 . 2
؟ ch 3 . 2
y؟ ch 4 . 2
y؟ ch 5 . 2
؟ ch 6 . 2
ch7 . 2 ؟
$
بديهي است که اين حلقه بايد برای تايپ زمان بعدی در يك فايل شل قرار داده شود :اگر شما چیزی را برای دوبار انجام دادهايد ،اين
احتمال وجود دارد که شما دوباره آن را انجام دهید.
تمرين ۳.۱۵اگر حلقة diffدريك فايل شل قرار داده شود ،آيا شما pickرا در فايل شل قرار ميدهید؟ چرا بله و چرا نه؟
تمرين ۳.۱۶چه اتفاقي ميافتد اگر سطر آخر حلقة بال به اين صورت باشد.
> done | pr | 'pr $
يعني اينکه با يك آمپرساند پايان پذيرد؟ ببینید آيا ميتوانید از آن سردر بیاوريد ،سپس آن را بررسي کنید.
برای اينکه بدانیم چگونه فايلهای شل گسترش مييابند ،با يك مثال بزرگتر کار ميکنیم .تصور کنید که پستي را از يك دوست از
دستگاهي ديگردريافت کردهايد ،که ميگويد somewhere!bobو يعني اينکه او ميخواهد کپيهايي از فايلهای شل در binشما را
داشته باشد .سادهترين راه برای فرستادن آنها ،برگرداندن پست است ،بنابراين شما با تايپ زير آغاز کنید:
$ cd /usr/you/bin
'*$ for i in 'pick
> do
> = = = = = = = =اين هست فايل echo = = = = = = = = = = = = = =$i
> cat $i
> done | mail / somewhere ! bob
$
اما از نقطه نظر somewhere ! bobبه آن نگاه کنید :او قصد دارد که يك پیغام پستي با همة فايلهايي که به وضوح مرزنمايي مي
شوند ،دريافت کند ،اما او بايد از يك ويراستار برای تبديل کردن آنها به فايلهای جزء استفاده کند .علمت دريافت اين است که يك
پیغام پستي به طور صحیح ساخته شده بتواند به طور اتوماتیك خود را باز کند ،در نتیجه گیرنده نبايد کاری انجام دهد .چنین چیزی دال
بر اين است که يك فايل شل بايد حاوی هردو فايل و دستورالعملهايي برای بازکردن آن باشد.
89/322 محیط برنامه سازی لینوکس
دومین دريافت اين است که اسناد در اينجای شل ،يك روش مناسب برای ترکیب يك درخواست فرمان و دادههای فرمان باشند .مابقي
کار ،فقط گرفتن نقل قولها به طور صحیح ميباشد .در اينجا يك برنامة کاربا عنوان bundleوجود دارد که فايلها را در يك فايل شل
خود توضیح بر روی خروجي استاندارد آن ،گروهبندی ميکند:
اگر يکي از فايلهايي که شما ميفرستید برحسب اتفاق دارای يك سطر به شکل زير باشد:
End of filename
مشکل وجود دارد ،اما اين يك اتفاق با احتمال بسیار پائین ميباشد .برای ايجاد يك بستة صرفا ً امن ،ما نیاز به يك يا دو مورد از
فصلهای بعدی داريم ،اما چنین چیزی به طور قابل توجهي ،قابل استفاده و مناسب ميباشد ،همانگونه که نشان ميدهد.
، bundleتغییرپذيری محیط يونیکس را شرح ميدهد نه bundleاز حلقههای شل ،جهت دهي مجدد ، I/Oاسناد موجود در اينجا و
فايلهای شل استفاده ميکندbundle.مستقیماً با پست ( )mailارتباط برقرار ميکند و شايد به طور جالبتر ،برنامهای است که يك برنامه
را بوجود مي آورد ،bundle .يکي از بهترين برنامههای شل ميباشد که ما ميشناسیم -سطرهای اندکي از رمز که هرچیزی را ساده،
مفید و دقیق انجام ميدهند.
تمرين .۳.۱۷شما چگونه از bunddleبرای فرستادن همة فايلها دريك فهرست و زيرفهرستهای آن استفاده ميکنید؟ توجه :فايلهای
شل ميتوانند بازگشتي باشند.
تمرين bunddle .۳.۱۸را به گونهای تغییر دهید که با هر فايل حاوی اطلعات ذخیره شده از 1ـ ، S1بويژه موارد مجاز و زمان آخرين
تغییر باشد .تسهیلت bunddleرابا برنامة بايگاني arمقايسه کنید.
شل يونیکس ،نمونة مفسران فرمان نميباشد :اگرچه اين امکان رابه شما ميدهد که فرمانها را در روش معمول اجرا کنید اما چون يك
زبان برنامهنويسي است ،ميتواند کارهای بیشتری انجام دهد .ارزش آن تا حدودی به چیزی برميگردد که ما در آن مشاهده کردهايم،
تاحدودی به اين دلیل که مطالب زيادی در اين فصل وجود دارد ،اما بیشتر به خاطر اينکه ما قول داديم که درخصوص «ويژگیهای
عموماً استفاده شده» صحبت کنیم و سپس حدود ۳۰صفحه در خصوص مثالتي مربوط به برنامه ريزی شل نوشتیم.
اما زماني که شما از شل استفاده ميکنید ،شما در تمام مدت ،مطالب اندکي درخصوص برنامههای يك سطری مينويسید :يك خط
لولهای ،يك برنامه است همانند اين مثال که «چای حاضراست» .شل به اين صورت کار ميکند :شما به طور مداوم به آن برنامه
ميدهید ،اما بسیار آسان و طبیعي است (همانگونه که شما با آن آشنا هستید) بطوری که شما نمي توانید به عنوان يك زبان برنامهنويسي
به آن فکر کنید.
شل بعضي از کارها را انجام ميدهد ،مانند حلقه سازی ،جهت دهي مجدد I/Oبا دو > و < گسترش اسم فايل با * ،بنابراين هیچ
برنامهای نگران اين کارها نميباشد و به طور مهمتر ،کاربرد اين تسهیلت درمیان همة برنامهها يکسان است.
ساير ويژگي ها ،مانند فايلها و لولههای شل ،حقیقتا ً توسط کرنل تهیه ميشوند ،اما شل برای ايجاد آنها دارای نمو طبیعي ميباشد .آنها
بیشتر از چیزی که مناسب است ،توانايي های سیستم را افزايش مي دهند.
قسمت اعظم قدرت و سهولت شل ،از کرنل يونیکسي مي باشد که در زير آن قرار دارد :برای مثال ،اگرچه شل ،لولهها را نصب ميکند
91/322 محیط برنامه سازی لینوکس
اماکرنل حقیقتا ً دادهها را به درون آنها وارد ميکند .روشي که بر طبق آن ،سیستم فايلهای قابل اجرا را بوجود مي آورد ،امکان نوشتن
فايلهای شل را بوجود ميآورد و در نتیجه آنها دقیقاً شبیه برنامههای کامپايل شده اجرا ميشوند .کاربر نبايد مطلع باشد که آنها فايلهای
فرمان هستند ـ به آنها با يك فرمان خاص مانن د RUNاستفاده نميشود .همچنین شل خودش يك برنامه است و بخشي از کرنل
نميباشد ،در نتیجه مي تواند تنظیم شود ،گسترش يابد و شبیه هر برنامة ديگری استفاده شود .اين عقیده برای سیستم يونیکس بينظیر
نمي باشد ،اما بهتر از هرجای ديگری استفاده شده است.
در فصل ۵ما به موضوع برنامه نويسي شل باز ميگرديم ،اما شما بايد به خاطر داشته باشید که هرکاری که شما با شل انجام ميدهید :
شما آن را برنامهنويسي ميکنید -به همین دلیل است که به خوبي کار ميکند .
شل ،از همان زمانهای اولیه ،قابل برنامه نويسي بوده است .در اصل ،فرمانهای مجزايي برای if ، gotoو lablesوجود داشتند و فرمان
gotoکه از طريق مرور فايل ورودی عمل ميکند ،از ابتدا به دنبال lableصحیح ميباشد( .چون اين امکان وجود ندارد که يك لوله
مجدد ًا خوانده شود ،اين امکان وجود ندارد که درون يك فايل شلي را لوله گذاری کنیم که دارای جريان کنترل بوده است).
هفتمین ويرايش شل ،در ابتدا توسط استیوبورن با کمك و عقايد جون ماشری همچنانکه در فصل ۵خواهیم ديد .به علوه ،ورودی و
خروجي توجیه ميشوند :اين امکان وجود دارد که I/Oرا در داخل و خارج ازبرنامههای شل بدون محدوديت ،تغییر جهت دهیم.
تجزية فراکاراکترهای اسم فايل نیز برای اين شل دروني ميباشد; تجزيه يك برنامة مجزا درنسخههای اولیه بوده است که بايد بر روی
ماشینهای خیلي کوچك قرار گیرد.
يك شل مهم ديگر ،که ممکن است شما در cshاجرا کنید (حتي ممکن است شما آن را ترجیحا ً استفاده کنید) شل Cميباشد که
دربرکلي توسط بیل جوی با ايجاد ششمین ويرايش شل ،توسعه يافت .شل ، Cبیشتر از شل بورن در جهت واکنش کمکي متقابل
استفاده شده است ـ بويژه اين شل ،يك مکانیسم تاريخي را فراهم ميکند امکان تکرار خلصه نويسي فرمانهايي را ميدهد که قبلً
صادر شدهاندـ (شايد با اندکي ويرايش) .نمو ،نیز ت ا حدودی متفاوت ميباشد .اما چون براساس ش ل قبلي ميباشد ،ازسهولت
برنامهنويسي کمتری برخوردار است؛ و نمو ،بیشتر يك مفسر فرمان محاورهای ميباشد تا يك زبا برنامهنويسي .بويژه ،اين امکان وجود
ندارد که در داخل يا خارج از ساختهای جريان کنترل را لولهگذاری کنیم.
Pickتوسط تام داف اختراع شد و bunddleبه طور مستقل توسط آلن هیرت و جیمز گاسلینگ اختراع شد.
92/322 محیط برنامه سازی لینوکس
93/322 محیط برنامه سازی لینوکس
فصل : 4فیلترها
يك خانواده بزرگ از برنامههای يونیکس وجود دارد که ورودی را ميخوانند ،يك تبديل ساده را بر روی آن انجام ميدهند و خروجي
را مينويسند .مثالهايي از اين قبیل شامل grepو tailميباشند که بخشي از ورودی را انتخاب ميکنند sort ،که آن را ترتیببندی
ميکند Wc ،که آن را ميشمرد و مواردی از اين قبیل .چنین برنامههايي ،فیلتر نامیده ميشوند.
اين فصل ،فیلترهايي را که غالباً مورد استفاده قرار ميگیرند مورد بحث و بررسي قرار ميدهد .ما با grepآغاز ميکنیم و بر طرحهايي
متمرکز ميشويم که پیچیدهتر از طرحهای شرح داده شده در فصل ۱ميباشند .ما همچنین به دو عضو ديگر از خانواده grepيعني
egrepو fgrepميپردازيم.
بخش بعد به طور خلصه تعدادی ديگر از فیلترهای مفید را توصیف ميکند که شامل trبرای حرفنگاری کاراکتر dd ،برای پرداختن
به دادههايي از ساير سیستمها و unigبرای آشکارسازی سطرهای تکرار شده متن ميباشند Sort .نیز به طور مفصلتر از فصل ۱ارائه
ميشود.
مابقي فصل ،به دو هدف کلي مبدلهای دادهها يا فیلترهای برنامهپذير ،اختصاص دارد .آنها به اين دلیل برنامهپذير نامیده ميشوند که
تبديل ويژه به عنوان يك برنامه در يك زبان ساده برنامهنويسي ،بیان ميشود .برنامههای متفاوت ميتوانند تبديلهای بسیار متفاوت را
بوجود آورند.
برنامهها عبارت از ، sedکه برای ويراستار جريان ميباشد و a w kکه پس از نويسندگانش ،نامگذاری ميشود ميباشند .هر دو
برنامه از يك تعمیم از grepمشتق ميشوند :
… $ program pattern – action filenames
فايلها را به طور متوالي پويش ميکند و به دنبال سطرهايي ميباشد که يك طرح را تطبیق ميدهند؛ زماني که کشف ميشود عملکرد
مربوطه انجام ميشود .برای ،grepطرح يك بیان منظم مانند edميباشد و عملکرد پیش فرض ،پرينت کردن هر سطری ميباشد که
طرح را تطبیق ميدهد.
sedو ، awkهم طرحها و هم عملکردها را تعمیم ميکنند ، Sed .يك مشتق از edميباشد و يك برنامه از فرمانهای ويراستار و
دادههای جرياني ميگیرد که از طريق فايلها از آنها عبور ميکنند و فرمانهای برنامه را روی هر سطر انجام ميدهند awk .برای
جايگزيني متن به سهولت sedنميباشد ،اما شامل حساب ،متغیرها ،تابعهای توکار و يك زبان برنامهنويسي ميباشد که اندکي شبیه به
زبان cاست .اين فصل دارای يك داستان کامل در مورد هر برنامه نميباشد و جلد ۲۰از کتاب راهنمای برنامهنويس يونیکس دارای
برنامههای آموزشي درخصوص هر دو برنامه ميباشد.
grep ۴.۱
ما در فصل ۱به طور خلصه در مورد grepذکر کرديم و از آن موقع از آن در مثالهايي استفاده کردهايم.
…$ grep pattern filp-nomes
به جستجوی فايلهای نامگذاری شده يا ورودی استاندارد ميپردازد و هر سطری را پرينت ميکند که شامل يك مورد از طرح باشد.
grepبرای پیدا کردن رخدادهای متغیرها در برنامهها و يا کلمات در اسناد و يا برای پیدا کردن قسمتهايي از خروجي يك برنامه ،ارزشي
ندارد :
94/322 محیط برنامه سازی لینوکس
انتخاب – ، nتعداد سطرها را پرينت ميکند ،انتخاب – ، vحس امتحان را تبديل ميکند و – yحروف جعبه پائیني را در حروف
تطبیق طرح همان جعبه در فايل ميسازد (جعبه باليي نیز فقط جعبه باليي را تطبیق ميدهد).
در همه مثالهايي که تاکنون مشاهده کردهايم grep ،به دنبال رشتههای معمولي حروف و اعداد بوده است .اما grepميتواند حقیقتا ً در
جستجوی طرحهای پیچیدهتر باشد ، grep :بیانها را در يك زبان ساده برای توصیف رشتهها تفسیر ميکند.
از نظر تکنیکي ،طرحها اندکي يك شکل محدود شده از مشخص کنندههای رشته ميباشند و عبارت منظم نامیده ميشوندGrep .
همان عبارت منظم مانند edرا تفسیر ميکند؛ در حقیقت grepدر ابتدا (در يك بعدازظهر) از طريق عمل مستقیم بر روی edبوجود
آمد.
عبارتهای منظم با دادن معني ويژه به کاراکترهای خاص ،مشخص ميشوند ،درست شبیه * و غیره که توسط شل استفاده ميشوند .فرا
کاراکترهای بیشتری وجود دارند و متاسفانه دارای تفاوتهايي در معاني خود ميباشند .جدول ۴.۱همه فراکاراکرهای عبارت منظم را
نشان ميدهد اما به طور خلصه در اينجا به مرور آنها ميپردازيم.
فرا کارکترهای ^ و $طرح را برای شروع (^) يا پايان ( )$سطر تثبیت ميکنند .برای مثال ،
$ grep From $ MAIL
فايلهايي را که شامل Fromميباشند در صندوق پستي شما قرار ميدهد اما
$ grep ′^ From′ $ MAIL
سطرهايي را پرينت ميکند که با Formآغاز ميشوند ،که به احتمال قوی سطرهايي با عنوان پیغام ميباشند .فراکاراکترهای عبارت
منظم ،با فراکاراکترهای شل همپوشاني ميکنند ،بنابراين همیشه يك عقیده خوب برای ضمیمه کردن طرحهای grepدر نقلهای منفرد
وجود دارد.
،grepطبقههايي از کاراکترها را حمايت ميکند که بسیار شبیه به کارکترهای موجود در شل ميباشند ،بنابراين [ ،]a-zهر گونه حرف
در جعبه پائیني را تطبیق ميکند .اما تفاوتهايي وجود دارند :اگر يك طبقه از کاراکتر grepبا يك سیرکومفلکس ^ ،آغاز شود طرح هر
کاراکتری را تطبیق ميکند ،به جز کاراکترهايي را که در طبقه وجود دارند .
بنابراين ]9– 0 ^ [ ،هر گونه کاراکتر غیر رقمي را تطبیق ميکند .همچنین در شل يك پس کج خط از lو ــ ،در يك طبقه از کاراکتر
محافظت ميکند ،اما grepو edمستلزم اين هستند که کاراکترها درجايي آشکار شوند که معني آنها مبهم نباشد .برای مثال]-[ ]sil[ ،
[ ] ،يك کروشه مربع بسته يا باز و يا يك علمت منها را تطبیق ميکند.
يك دوره « » .معادل ؟ شل ميباشد :هر گونه کاراکتری را تطبیق ميکند( .دوره احتمال کاراکتر با متفاوتترين معني برای برنامههای
95/322 محیط برنامه سازی لینوکس
وجود دارند + .و ؟ .طرح x +يك يا چند x’sرا تطبيق ميكند و ? xصفر يا يك xرا تطبيق
ميكند و نه بيشتر.
، Grepت تدرت تبازيت تكلماتت تعاليت تاستت توت تشاملت تجستجويت تفرهنگت تلغتت تبرايت تكلماتت تبا
ويژگيهاي خاص ميباشد .فرهنگ لغت ما دومين و بستر بين المللي ميباشد و به عنوان
فهرستي از لغات ،در هر سطر و بدون تعريف ترتيب بندي ميشود .سيستم شما ممكن
است داراي usr/dict/words /باشد ،يك فرهنگ لغت كوچكتر كه به كنترل تلفظ ميپردازد:
براي كنترل فرمت به آن نگاه كنيد .دراينجا يك طرح براي پيدا كردن لغاتي وجوددارد كه حاوی
۵و اول در ترتيب الفبايي ميباشند :
$ cat alphvowels
^ ]^ aeio[ * a ] ^ a eiou[ * e ] ^ aeiou [ * i ]^ a eiou * o ] ^ a eiou[ * a
] ^ aeio[ * $
$ egrep – f alphrowels / usr / dict / web 2 | 3
abstemious abstemiously abstentious
acheilous acheirous acleistous
affectious annelidiou arsenious
arterious bacterious caesoious
facetious facetiously fracedinous
majectious
$
طرح ،در واولهای الفبايي فايل ،ضمیمه نقل قولها نميشود .زماني که نقل قولها برای ضمیمه کردن طرحهای egrepاستفاده ميشوند،
مثل فرمانها را از تفسیر شدن حفظ ميکند اما نقل قولها را قطع ميکند؛ egrepهرگز آنها را نميبیند .چون فايل توسط شل بررسي
نميشود ،نقل قولها در اطراف محتواهای آن استفاده نميشوند .ما ميتوانستیم از grepبرای اين مثال استفاده کنیم ،اما به خاطر روشي
که بر طبق آن egrepکار ميکند ،زماني که به جستجوی طرحهايي بپردازيم که شامل بستار ميباشند ،اين کار سريعتر انجام ميشود،
بويژه زماني که فايلهای بزرگ را پويش ميکنیم.
به عنوان مثال ديگر ،پیدا کردن همه کلمات شش حرفي يا بیشتر ميباشد که در ترتیب الفبايي دارای حرف ميباشند :
$ cat monotonic
^a ? b ? c ? d ? e ? f ? g ? h ? i ? j ? k ? l ? m ? n ? o ? p ? q ? r ? s ? t ? u ? v ? w? x ? y ? z ? $
$ egrep – f monotonic / usr / dict / web 2 | grep ′………′ | 5
abdest acknow adipsy agnosy almost
befist behint beknow bijoux biopsy
chinte debors dehort deinos dimpsy
egilops ghosty
$
( ، egilopsيك نوع بیماری است که به گندم حمله ميکند) .توجه داشته باشید که استفاده از grepبرای فیلتر کردن خروجي grep
ميباشد.
چرا سه برنامه grepوجود دارد؟ ، fgrepهيچ فرا كاراكتري را تفسير نميكند اما ميتواند
به طور موثر به دنبال هزاران لغت به صورت موازي باشد (زماني كه آغاز ميشود .زمان
اجراي تآن تمستقل تاز تتعداد تكلمات تميباشد) وت تبنابراين ت،ت تدر تابتدا تبراي توظايفي تمانند
جستجوهايت تكتابت تشناسيت تاستفادهت تميشود .اندازهت تطرحهايت تاصليت ،fgrepت تمافوق
ظرفيت تآلگوريتمهاي تاستفاده تشده تدرت grepوت egrepميباشد .تمايز تبينت grepوت egrepبه
97/322 محیط برنامه سازی لینوکس
سختي قابل توجيه است ،grep .اندكي زودتر ميآيد ،عبارات منظم آشنا را از edميگيرد
و بر روي عبارات منظم و يك مجموعه وسيعتري از انتخابها علمت زده است egrep .عبارات
كليتر را تفسير ميكند ( به جز براي علمت زدن) و به طور حائز اهميتي سريعتر اجرا
ميكند (با سرعتي مستقل از طرح) ،امانسخه استاندارد ،زمان بيشتري را براي شروع
ميگيرد تزماني تكه تعبارت تپيچيده تاست .يك تنسخه تجديدتر توجود تدارد تكه تسريعاً تآغاز
ميشود ،بنابراين egrepو grepميتوانند اكنون به يك طرح واحد تبديل شوند كه برنامه را تطبيق
ميكند.
تمرين . ۴.۲ساختار grepبرای خواندن يك سطر مفرد ميباشد ،آن را برای تطبیق کنترل کنید ،سپس آن را حلقه سازی کنیدgrep .
چگونه تحت تأثیر قرار ميگیرد اگر عبارات منظم بتوانند سطرهای جديد را تطبیق دهند؟
۴.۲ساير فیلترها
هدف اين بخش ،آگاه کردن شما درخصوص وجود و تواناييهای يك مجموعه غني از فیلترهای کوچکي ميباشد که توسط سیستم
98/322 محیط برنامه سازی لینوکس
تهیه ميشوند و ارائه مثالهايي درخصوص استفاده از آنها ميباشد .اين فهرست به هیچ وجه کامل نميباشد ـ تعداد زياد ديگری نیز
هستند که بخشي از هفتمین ويرايش بودند و هر نصب ،بخشي از خودش را بوجود ميآورد .همه فیلترهای استاندارد در بخش اول
کتاب راهنما توصیف ميشوند.
ما با sortآغاز ميکنیم که احتمال ً مفیدترين آنها مي باشد .اصول اولیه sortدر فصل اول ،ارائه شدند ، sort :ورودی خود را با يك
سطر در ترتیب ASCIIترتیببندی ميکند .اگر چه اين يك مورد بديهي است که با پیش فرض انجام ميشود ،اما راههای بسیار
ديگری نیز وجود دارند که فرد ميخواهد از آن طريق دادهها را ترتیببندی کند و sortدرصدد فراهم کردن اين راهها از طريق ارائه
انتخابهای متفاوت برای آنها ميباشد .برای مثال ،انتخاب – ، fباعث ميشود که جعبه باليي و پائیني تا شوند و در نتیجه تفاوتهای
جعبه حذف ميشوند .انتخاب –( dبه ترتیب فرهنگ لغت) همه کاراکترها به جز حروف ،ارقام و فاصله در مقايسهها را ناديده ميگیرد.
اگر چه مقايسههای الفبايي بسیار عمومي هستند ،اما گاهي اوقات يك مقايسه عددی لزم است .انتخاب – nتوسط ارزش عددی
ترتیب بندی ميکند و انتخاب – rحس هر گونه مقايسهای را تغییر ميدهد .بنابراين ،
s | sort – f / $ اسامي فايلها را به ترتيب الفبايي ترتيب بندي ميكند
s | sort – n / $ با كوچكترين فايلها مرتب ميكند
s - s | sort – nr / $ با بزرگترين فايلها مرتب ميكند
، sortدر حالت عادی بر روی يك سطر کامل ترتیببندی ميکند ،اما ميتوان گفت که توجه خود را فقط به زمینههای خاص متمرکز
ميکند .نماد +mبه معنای اين است که مقايسه از اولین زمینههای mجست ميزند؛ +oآغاز سطر است .بنابراين ،برای مثال،
s - 1 | sort + 3 nr / $ با شمارش بايت ،از بزرگترين مرتب ميشود
who | sort + 4n $ با زمان ، loginاز قديميترين مرتب ميشود
ساير انتخابهای مفید sortشامل - oميباشند که يك اسم فايل را برای خروجي مشخص ميکند (اين انتخاب ميتواند يکي از فايلهای
ورودی باشد) و - uکه همه ،به جز يکي از گروههای سطرها را که در زمینههای sortمشابه هستند ،حذف ميکند.
کلیدهای متعدد sortميتوانند استفاده شوند ،همچنانکه با اين مثال رمزی از sortصفحه کتاب راهنما شرح داده ميشود :
$ sort + of + o - u filenames
، + ofسطر را مرتب ميکند ،جعبه باليي و پائیني را با هم تا ميکند ،اما سطرهايي که مشابه هستند ،نميتوانند مجاور هم باشند .
بنابراين + oدومین کلید است که سطرهای يکسان از اولین sortرا در ترتیب عادی ASCIIمرتب ميکند .در آخر -u ،نسخههای
مجاور را از هم جدا ميکند .بنابراين با توجه به فهرست کلمات و هر سطر ،فرمان ،لغات بينظیری را پرينت ميکند .شاخص برای اين
کتاب با يك فرمان sortمشابه تهیه شد ،که حتي بیشتر ،از تواناييهای sortاستفاده ميکند .به sortcuمراجعه کنید.
فرمان ، uniqالهام برای نشانه ـ -uاز sortميباشد :اين فرمان ،همه ،به جز يك گروه از سطرهای نسخهای مجاور را از هم جدا
ميکند .داشتن يك برنامه مجزا برای اين عملکرد منجر به انجام وظايف بدون ارتباط با ترتیببندی ميشود .برای مثال،ـ ، uniq
سطرهای فاصله متعدد را حذف ميکند ،حال چه ورودی آن مرتب شود و چه مرتب نشود.
99/322 محیط برنامه سازی لینوکس
انتخابها به روشهای خاصي برای پردازش نسخهها استفاده ميکنند uniq - d :فقط سطرهايي را پرينت ميکند که دو نسخهای ميشوند
؛ uniq-uفقط سطرهايي را پرينت ميکند که بينظیر ميباشند( .يعني دو نسخهای نميباشند) و uniq- cتعداد رخدادهای هر سطر را
ميشمارد.
ما به يك مثال به طور خلصه مراجعه خواهیم کرد.
فرمان commيك برنامه مقايسه فايل ميباشد .با توجه به دو فايل ورودي مرتب شده f1و f
2 ، commسه ستون از خروجي را پرينت ميكند :
يدهند ،سطرهايي كه فقط در f2رخ ميدهند و سطرهايي سطرهايي كه فقط در f1رخ م
كه در هر دو فايل رخ ميدهند .هر كدام از اين ستونها ميتوانند توسط يك انتخاب حذف
شوند :
$ comm – 12 f1 f2
فقط سطرهايي را پرينت ميکند که در هر دو فايل قرار دارند و
$ comm – 23 f1f2
سطرهايي را پرينت ميکند که در اولین فايل وجود دارند ،اما در دومین فايل نميباشند .چنین چیزی برای مقايسه فهرست ها را برای
مقايسه يك فهرست کلمه با يك فرهنگ لغت ،مفید است.
فرمان ،trکاراکترها را در ورودی خودش ترجمه ميکند .تاکنون عموميترين استفاده از ،trتبديل مورد ميباشد :
tr a- Z A - Z $ از مورد پائین به مورد باليي مينگارد
tr AZ a – Z $ از مورد باليي به مورد پائیني مينگارد
فرمانـ ddتا حدودی متفاوت از ساير فرمانهايي ميباشد که ما ديدهايم .اين فرمان در ابتدا فقط قصد بررسي دادههای نوار را از
سیستمهای ديگر دارد ـ نام آن يك باقیمانده از زبان کنترل کار os /360ميباشد ،dd .تبديل مورد را انجام ميدهد (با يك نحو خیلي
متفاوت از )tr؛ ،ddاز ASCIIبه EBCDICو بالعکس تبديل ميکند؛ و دادهها را در ثبتیاتي با اندازه ثابت ،با سبط دهي فاصلهای که
سیستمهای غیر يونیکس را توصیف ميکنند ،ميخواند يا مينويسد .در عمل dd ،اغلب برای پرداختن به دادههای خام و فرمت نشده
استفاده ميشود ،با هر منبعي که باشند؛ ، ddيك مجموعه از امکانات را برای پرداختن به دادههای دوگانه ،آشکار ميسازد.
برای شرح چیزی که ميتوان با ترکیب فیلترها انجام داد ،خط لولهای زير را در نظر بگیريد ،که غالبا 10کلمه را در ورودی خود پرينت
ميکند :
cat | * $
|'tr – sc A-za-z '\ 012 اجراهای غير حرفی را در سطر جدید متراکم کنيد
| sort
| uniq – c
| sort – n
| tail
5
100/322 محیط برنامه سازی لینوکس
، catفايلها را جمعآوری ميکند ،چون ، trفقط ورودی استاندارد خود را ميخواند ،فرمان ، trاز کتاب راهنما ميباشد :اين فرمان
موارد غیر حرفي مجاور را در سطرهای جديد متراکم ميکند ،بنابراين ،ورودی را به يك کلمه درهر سطر تبديل ميکند .کلمات در
نتیجه مرتب ميشوند و uniq-cهر گروه از کلمات مشابه را در يك سطری متراکم ميکند که دارای پیشوند تعداد ميباشد و برای sort
، – nبه زمینه ترتیب بندی تبديل ميشود( .اين ترکیب از دو ترتیببندی در اطراف يك uniqکه اغلب رخ ميدهد ،يك شیوه نامیده
ميشود) .نتیجه ،کلمات بينظیر در سند ميشود که درتکرار در حال افزايش مرتب ميشوندtail، ۱۰ .مورد از عموميترين کلمات را
انتخاب ميکند (انتهای فهرست مرتب شده) و ۵آنها را در ۵ستون پرينت ميکند.
در ضمن ،توجه داشته باشید که اتمام يك سطر با | ،يك روش معتبر برای ادامه آن ميباشد.
تمرين .۴.۳در اين بخش از ابزار برای نوشتن يك کنترل کننده ساده تلفظ ،با استفاده از
usr/ dict / words /استفاده کنید .کمبودهای آن چیست و شما چگونه آنها را مورد خطاب قرار ميدهید؟
تمرين .۴.۴يك برنامه شمارش کلمه به زبان برنامهنويسي مورد علقه خود بنويسید و اندازه ،سرعت و قابلیت حفظ آن را با خط
لولهای شمارش کلمه مقايسه کنید .چقدر آسان شما ميتوانید آن را به يك کنترل کننده تلفظ تبديل کنید ؟
اکنون به سراغ sedميرويم .چون sedمستقیما ً از edمشتق ميشود ،يادگیری آن بايد آسان باشد و sedآگاهي شما را در مورد ، ed
تقويت ميکند .ايده اصلي درخصوص sedساده است :
… $ sed ′ list of ed commands ′ filenames
سطرها را از فايلهای ورودی ميخواند البته در هر زمان يك سطر ؛ فرمانهايي را از فهرست برای هر سطر بکار ميبرد و شکل ويرايش
شده آن را بر روی خروجي استاندارد مينويسد .بنابراين ،برای مثال ،شما ميتوانید يونیکس را به يونیکس ( ) tmتبديل کنید .در
هرجايي که در يك مجموعه از فايلها با فرمان زير رخ ميدهد :
$ sed ′ s / unix / unix )Tm( / g′ filenames … > output
چیزی را که در اينجا رخ ميدهد به غلط تفسیر نکنید ،Sed .محتواهای فايلهای ورودی خود را تغییر نميدهد Sed .بر روی خروجي
استاندارد مينويسد ،در نتیجه ،فايلهای اصلي تغییر نميکنند .اکنون شما تجربه کافي درخصوص مثل داريد برای اينکه پي ببريد که
$ sed ′ … ′ file > file
يك ايده خوبي نیست :برای جايگزين کردن محتواهای فايلها ،شما بايد از يك فايل موقت يا برنامهای ديگر استفاده کنید( .ما بعداً در
مورد يك برنامه برای آشکار کردن ديده مربوط به روی هم نوشتن يك فايل موجود صحبت خواهیم کرد؛ به روی همنويسي در فصل ۵
مراجعه کنید).
Sedهر سطر به صورت اتوماتیك خارج ميشود ،در نتیجه بهـ pپس از جايگزيني فرمان بال نیازی نیست؛ حقیقتاًـ اگر يكـ p
وجودداشت ،هر سطر اصلح شده ،دو بار پرينت ميشد .نقل قولها تقريبا ً همیشه لزم هستند ،چونبسیاری از فراکاراکترهای sedبرای
شل دارای معني ميباشند .برای مثال ،استفاده از du – aرا برای ايجاد يك فهرست از اسامي فايلها در نظر بگیريد .در حالت عادیda ،
ـ اندازه و اسم فايل را پرينت ميکند :
$ * du – a ch 4 .
101/322 محیط برنامه سازی لینوکس
جايگزيني همه كاراكترهاي ( * )0را حذف ميكند و شامل راستترين سمت جدولبندي
ميباشد (كه در نمونه به صورت نشان داده ميشود).
در يك روش مشابه ،شما ميتوانید اسامي کاربرها و زمانهای loginرا از خروجي whoانتخاب کنید :
$ who
1r tty1 sep 29 07 : 14
ron tty3 sep 29 10 : 31
you tty4 sep 29 08 : 36
td tty5 sep 29 08 : 47
$ who | sed ′s / . * // ′
1r 07 : 14
ron 10 : 31
you 08 : 36
td 08 : 47
$
فرمان sيك جای خالي را جايگزين ميکند و هر چیزی را که تا فاصله بعدی توسط يك فاصله تنها به دنبال آن ميآيد (تا جايي که
امکانپذير است شامل اکثر فاصلهها ميباشد) .دوباره نقلقولها لزم هستند.
تقريبا همان فرمان sedميتواند برای ايجاد يك برنامه getnameاستفاده شود که نام کاربر شما را بر ميگرداند :
$ cat getname
who am : | sed ′ s / . * // ′
$ getname
you
$
توالي ديگر sedکه غالباً استفاده ميشود اين است که ما آن را در يك فايل شل با عنوان indساختهايم .فرمان ،indدرورودی خود يك
102/322 محیط برنامه سازی لینوکس
ايست جدولبندی را فاصلهگذاری ميکند؛ اين فرمان برای حرکت دادن چیزی به منظور ايجاد تناسب بهتر بر روی صفحه چاپگر سطر
مفید و مناسب است.
اجرای indآسان است ـ يك جدول بندی در جلوی هر سطر بچسبانید :
* $ sed ′ s / ^ / → / ′ نسخه 1از ind
اين نسخه يك جدولبندی را بر روی هر سطر خالي نیز قرار ميدهد که به نظر غیرضروری ميرسد .يك نسخه بهتر از توانايي sed
برای انتخاب سطرهايي استفاده ميکند که بايد تغییر داده شوند .اگر شمايك طرح برای فرمان به صورت پیشوندقرار دهید ،فقط
سطرهايي که طرح را تطبیق ميکنند تحت تأثیر قرار ميگیرند :
* $ sed ′ /.s / ^ / → / ′ نسخه ۲از ind
طرح ، /. /هر سطری را تطبیق ميدهد که حداقل دارای يك کاراکتر بر روی خود غیر از يك سطر جديد ميباشد؛ فرمان sبرای آن
سطرها انجام ميشود اما برای سطرهای خالي اجرا نميشود .به خاطر داشته باشید که ، sedهمه سطرها را بدون توجه به اينکه آيا آنها
تغییر کردهاند يا نه ،خارج ميکند ،در نتیجه سطرهای خالي به همان صورتي به وجود ميآيند که بايد باشند.
هنوز يك راه ديگر برای نوشتن indوجود دارد .اين امکان وجود دارد که فرمانها فقط بر روی سطرهايي انجام شوند که طرح منتخب
را تطبیق نميکنند ،با قرار دادن يك علمت تعجب ! قبل از فرمان .در
* $ sed ′/ ^ $ / ! s / ^ / → / ′ نسخه ۳از ind
طرح ، /$ ^ /سطرهای خالي را تطبیق ميدهد (انتهای سطر سريعا با آغاز سطر دنبال ميشود) ،بنابراين ، says ! / $ ^ /فرمان را بر
روی سطرهای خالي اجرا نميکند.
همانگونه که در بال گفتیم ،sed ،هر سطر را به طور اتوماتیك پرينت ميکند ،بدون توجه به اينکه چه چیزی درخصوص آن انجام شده
است (مگر اينکه حذف شود) .به علوه ،اکثر فرمانهای edميتوانند استفاده شوند .بنابراين ،نوشتن يك برنامه sedکه سر سطر اول
ورودی خود ( )sayرا پرينت ميکند ،آسان است ،سپس از سیستم خارج شويد :
sed 3 q
اگر چه 3qيك فرمان edمجاز نميباشد ،اما در sedحس بوجود ميآورد :
سطرهای کپي ،در نتیجه پس از سومین فرمان از سیستم خارج ميشوند.
شما ميخواهید پردازش ديگری را برای دادهها انجام دهید ،مانند گذاشتن فاصله (تورفتگي) برای آن .يك راه برای انجام اين کار،
اجرای خروجي از sedاز طريق indميباشد ،اما چون sedفرمانهای متعدد را ميپذيرد ،چنین چیزی را ميتوان با يك درخواست تنها
(که تا حدودی بعید به نظر ميرسد) از sedانجام داد :
sed ′s/^/→/
3q′
توجه به جايي که نقل قولها و سطر جديد قرار دارند ،داشته باشید :فرمانها بايد بر روی سطرهای مجزا باشند .اما sedفاصلههای اصلي
و جدول بندیها را ناديده ميگیرد.
با اين عقايد ،نوشتن يك برنامه با عنوان ،headبرای پرينت سطرهای اولیه از هر آرگومان اسم فايل ،محسوس به نظر ميرسد .اما sed
( 3qبا )10qبرای تايپ کردن آنقدر آسان است که ما هرگز نیاز آن را حس نکردهايم .اما ،ما يك indاجرا ميکنیم ،چون فرمان sed
معادل آن برای تايپ ،دشوارتر است( .در فرآيند نوشتن اين کتاب ما برنامه ۳۰سطری cرا با دومین نسخه از اجراهای يك سطری که
103/322 محیط برنامه سازی لینوکس
قبل نشان داده شده است،جايگزين کرديم) .ملك آشکاری در اين خصوص وجود ندارد که چه موقع ايجاد يك فرمان مجزا از يك
سطر فرمان پیچیده با ارزش است؛ بهترين قاعدهای که ما پیدا کردهايم ،قرار دادن آن د ر binخود و مشاهده استفاده واقعي از آن
ميباشد.
همچنین اين امکان وجود دارد که فرمانهای sedرا در يك فايل قرار دهیم و آنها را از آنجا با فرمان
… sed – f cmd file $
اجرا کنیم.
شما ميتوانید از گزينش گران سطر غیر از اعدادی مانند ۳استفاده کنید :
$ sed ′ / pattern / q′
ورودی خود را پرينت ميکند و دارای طرح تطبیق کننده اولین سطر ميباشد و
$ sed ′ / pattern / d ′
هر سطری را که شامل patternباشد ،حذف ميکند؛ حذف قبل از اينکه سطر به طور اتوماتیك پرينت شود رخ ميدهد ،در نتیجه
سطرهای حذف شده ،جدا ميشوند.
اگر چه پرينت خودکار معمول ً مناسب ميباشد ،اما گاهي اوقات نیاز به روش دارد .پرينت خودکار ميتواند با انتخاب ، c-nخاموش
شود؛ در اين حالت ،فقط سطرهايي که آشکارا با يك فرمان Pپرينت ميشوند در خروجي ظاهر ميشوند.
،براي مثال $ sed – n ′ / pattern / p′
كاري را انجام ميدهد كه grepانجام ميدهد .چون شرايط تطبيق ميتواند با دنبال شدن
sed – n ′ / pattern / ! p′ $ آن با ! معكوس شود ،در نتيجه
يك grep – vميباشد (و در نتيجه فرمان sed ′ / pattern / d′ميباشد).
چرا ما هر دوی sedو grepرا داريم؟ بعد از همه اين موارد grep ،فقط يك مورد خاص از sedميباشد .بخشي از علت آن به خاطر
تاريخچه آن ميباشد ـ grepقبل از sedآمد .اما grepباقي ميماند و به راستي توسعه مييابد ،چون برای کار ويژهای که هر دوی آنها
انجام ميدهند ،اساساً استفاده از sedآسانتر است ، grep :مورد عمومي تا جايي که امکان دارد به طور مختصر انجام ميدهد، grep( .
همچنین کارهای ديگری را که sedانجام نميدهد .انجام ميدهد :برای نمونه به انتخاب -bنگاه کنید) .اما برنامهها از بین ميروند.
زماني برنامهای وجود داشت که gresنامیده ميشد و جايگزيني ساده را انجام ميداد ،اما تقريبا خیلي سريع منقضي شد ،زماني که sed
بوجود آمد.
سطرهای جديد ميتوانند با sedو با استفاده از همان نحو edدرج شوند:
\ $ sed ′ s / $ /
>/′
يك سطر جديد را به انتهاي هر سطر اضافه ميكند ،در نتيجه فاصله دوبل به ورودي آن
\ / * ]sed ′ s / ] →[ ]→ $ اضافه ميشود و
<g′/
هر رشته از فاصلههاي خالي يا جدولبنديها را با يك سطر جديد جايگزين ميكند و در
104/322 محیط برنامه سازی لینوکس
نتيجه ورودي خود را در يك كلمه در هر سطر ،تقسيم ميكند( .عبارت منظم ' [→] ' ،يك
فاصله يا جدولبندي را تطبيق ميكند ؛ ‘ [→] * ' تعداد صفر يا چند تا از اين فاصلهها يا
جدولبنديها را تطبيق ميكند ،بنابراين كل طرح يك يا چند فاصله و يا چند جدولبندي را
تطبيق ميكند.
همچنین شما ميتوانید جفتهايي از عبارات منظم يا شمارههای سطر را برای انتخاب يك دامنه از سطرهايي بکار ببريد که بر روی آنها
يکي از فرمانها عمل ميکنند.
شمارههای سطر از آغاز ورودی ميآيند؛ آنها در آغاز يك سطر جديد رسیت نميشوند .اما يك محدوديت مهم از sedوجوددارد که
مشترك با edنميباشد :شمارههای نسبي سطر حفظ نميشوند .بويژه + ،و … در عبارتهای شماره سطر درك نميشوند ،بنابراين،
رسیدن به عقبروها در ورودی امکانپذير نميباشد.
زماني که يك سطر خوانده ميشود ،سطر قبلي برای همیشه پاك ميشود :هیچ راهي برای شناسايي سطر بعد از قبلي وجود ندارد،
يعني چیزی که اين فرمان نیاز دارد( .به طور عادلنه ،يك راه برای کارکردن آن با sedوجود دارد ،اما اين راه خیلي پیشرفته است .به
فرمان « »holdدر کتاب راهنما مراجعه کنید) .همچنین راهي برای انجام نشاني دهي نسبي به طرف جلو وجود ندارد:
نميتواند به جلورو استناد شود :غیر مجاز
$ sed ′ / thing / + d′
، sedتوانايي خواندن بر روی فايلهای خروجي متعدد را فراهم ميکند .برای مثال ،
$ sed – n ′ / pat / w file /
… / pat / ! w file r′ filenames
سطرهايي را مينويسد که patروی فايل 1را تطبیق ميدهند و سطرهايي که patروی فايل ۲را تطبیق نميدهند .يا برای مشاهده
مجدد اولین مثال ما ،
105/322 محیط برنامه سازی لینوکس
نقل قولها ،از کاراکترهای خاص و متعدد هدف دار در sedمحافظت ميکنند؛ زماني که در معرض حذف 1 $قرار ميگیرند ،در نتیجه
شل آن را با اسم فايل جايگزين ميکند .يك روش ديگر برای نوشتن آرگومان به اين شکل ميباشد :
″/^$|\$q″
چون / $با آرگومان جايگزين ميشود زماني که \ $فقط به $تبديل ميشود .به همین روش ،ما ميتوانیم olderرا بنويسیم که همه
فايلهای قديميتر از فايلهای نامگذاری شده را لیست ميکند :
$ cat older
# older f : list files older than f
Is – tr | sed ′ / ^ ′ $ | ′ $ / q′
تنها تفاوت انتخاب - rبر روی ISبرای معکوس کردن ترتیب ،ميباشد.
اگرچه ،sedخیلي بیشتر از چیزهايي که شرح داديم انجام ميدهد ،شامل بررسي شرايط ،حلقهسازی و منشعب کردن ،به خاطر آوردن
سطرهای قبلي و البته بسیاری از فرمانهای edکه در ضمیمه ۱توصیف ميشوند ـ اما قسمت اعظم استفاده ،sedشبیه به چیزی است که
ما در اين جا نشان دادهايم ـ يك يا دو فرمان ساده ويرايش ـ و چیزی غیر از تواليهای بلند يا پیچیده ميباشد .جدول ، ۴.۲برخي از
تواناييهای sedرا به طور خلصه بیان ميکند ،اگر چه ،عملکردهای چند سطری در اين جدول حذف است.
Sedمناسب و آسان است چون به صورت اختیاری مي تواند با ورودیهای بلند کار کند ،چون سريع است و چون شبیه به edبا
عبارتهای منظم و پردازش يك سطر در يك زمان آن ميباشد .اما روی ديگر سکه sed ،ـ يك شکل نسبتا محدود از حافظه را فراهم
ميکند (به خاطر آوردن متن از يك سطر تا سطری ديگر دشوار است) sed ،فقط يك عبور از دادهها را امکانپذير ميسازد ،برگشتن به
عقب امکان پذير نميباشد ،راهي برای انجام ارجاعات به سمت جلو مانند ، / … / +1وجود ندارد و sedتسهیلتي را برای کار
کردن با شمارهها فراهم نميکند ـ sedصرف ًا يك ويراستار متن ميباشد.
تمرين Older .۴. ۵و Newerرا به گونهای تغییر دهید که ديگر دارای فايل آرگومان در خروجي خود نباشند .آنها را به گونهای تغییر
دهید که فايلها در يك ترتیب مخالف فهرستبندی شوند.
تمرين .۴.۶از sedبرای استحکام bundleاستفاده کنید .توجه :در اسناد موجود در اينجا ،کلمه نشان پايان ،فقط زماني شناسايي
ميشود که سطر را به طور دقیق تطبیق کند.
همان کاری را انجام ميدهد که مثال قبلي انجام ميدهد .به طور معکوس ،اگر طرح حذف شود .در نتیجه بخش عملکرد برای هر سطر
ورودی انجام ميشود .بنابراين
$ awk … ′} print{ ′ filenames
چیزی را انجام ميدهد که catانجام ميدهد ،ولو اينکه کندتر انجام ميدهد.
و اما نکته نهايي ،قبل از اينکه به مثالهای جالب بپردازيم .همانند ،sedاين امکان وجود دارد که برنامه را برای awkاز يك فايل ارائه
دهیم :
$ awk – f cmd file filenames ….
ميدانها
awkبه طور خودکار هر سطر ورودی را به میدانها تقسیم ميکند ،يعني رشتههايي از کاراکترهای بدون فاصله که توسط فاصلهها يا
جدولبندیها از هم جدا ميشوند .با اين تعريف ،خروجي whoدارای پنج میدان ميباشد :
$ who
you tty 2 sep 29 11 : 35
jim tty 4 sep 29 11 : 27
$
awkمیدانهای $2 ، $1و … ، NF $را ميخواند NF ،متغیری است که ارزش آن برای تعداد میدانها معین ميشود .در اين مورد ،
NFبرای هر دو سطر ۵ميباشد ( .به تفاوت بین ، NFعداد میدانها و ،$ NFيعني آخرين میدان بر روی سطر توجه کنید .در ،awk
بر خلف شل ،فقط میدانها با يك $آغاز ميشوند؛ متغیرها ساده هستند) .برای مثال ،برای جدا کردن اندازههای فايل ايجاد شده توسط
du-a
$ du – a | awk ′ } print $ 2 {′
و برای پرينت اسامي افراد وارد شده به سیستم و زمان ، loginدر يك سطر :
$ who | awk ′ } print $ 1 , $ 5 {′
you 11 : 53
jim 11 : 27
$
برای پرينت نام و زمان loginترتیب بندی شده توسط زمان :
فايل کلمه رمز ، etc / passwd /توسط «دو نقطهها» از هم جدا ميشوند.
$ sed 3 g / etc / passwd
root : 30 . FHR 5 KOB. 3 s : 0 : 1 : S . user : / :
ken : y – 68 wd 10 ijayz : 6 : 1 : k . Thompson : / usr / ken :
dmr ; z 4 a 3 d j w bg v w c k : v : 1 : D-M. Ritchie : / usr / dmr :
$
برای پرينت کردن اسامي کاربرها ،که از اولین میدان ميآيند ،
$ sed 3 q / etc / passwd | awk – f : ′ } print $ 1{ ′
root
ken
dmr
$
استفاده از فاصلهها وجدولبندیها ،تعمدا ً خاص ميباشد .توسط پیش فرض ،هم فاصلهها و هم جدولبندیها ،جداساز هستند و
جداسازهای اصلي جدا ميشوند .اگر جداساز ،برای هر چیزی غیر از فاصله تنظیم شود ،در نتیجه ،جداسازیهای اصلي در تعیین
میدانها ،به حساب آورده ميشوند .در اصل ،اگر جداساز ،يك جدول بندی باشد ،در نتیجه فاصلهها ،کاراکترهای جداساز نميباشند.
فاصلههای اصلي بخشي از میدان ميباشند و هر جدول بندی ،يك میدان را تعريف ميکند.
چاپ
، awkرد کمیتهای جالب را در کنار تعداد میدانهای ورودی حفظ ميکند .متغیر توکارـ ، NRتعداد رکورد ورودی جاری يا سطر
ميباشد .در نتیجه برای افزودن تعداد سطرها به يك جريان ورودی ،از عبارت زير استفاده کنید :
$ awk ′ } print NR , $ o {′
میدان ، $0کل سطر ورودی ،بدون تغییر ميباشد .در يك بیان ،printاقلم که توسط کاماها از هم جدا ميشوند ،به طور مجزا توسط
جداساز میدان خروجي چاپ ميشوند که توسط پیشفرض ،يك فاصله خالي ميباشد.
فرمت کردن که printآن را انجام ميدهد ،اغلب قابل قبول ميباشد ،اما اگر قابل قبول نباشد ،شما ميتوانید از يك بیان با عنوان print
fبرای کنترل کامل خروجي خود استفاده کنید .برای مثال ،برای چاپ تعداد سطرها در يك میدان با چهار رقم پهنا ،شما ميتوانید از
عبارت زير استفاده کنید:
$ awk ′ } print f ″ % 4 d % s \ n ″ , nR , $o {′
4d %يك عدد صحیح دهدهي ( )NRرا در يك میدان با چهار رقم پهنا ،مشخص ميکند S % ،يك رشته ازکاراکترها ( )$0را و \n
يك کاراکتر از سطر جديد را مشخص ميکنند ،چون ،print fهیچ فاصله يا سطر جديدی را به طور خودکار چاپ نميکند .بیان print
fدر awkشبیه عملکرد cميباشد; به )print f )۳مراجعه کنید.
ما توانستیم اولین نسخه ( indاز ابتدا در اين فصل) را به صورت زير بنويسیم
* awk ′ } print f ″ \ t % s \ n ″ , $o { ′ $
که يك جدولبندی ( )\ tو رکورد ورودی را چاپ ميکند.
109/322 محیط برنامه سازی لینوکس
طرحها
فرض کنید شما ميخواهید به عبارت etc / passwd /در جستجوی افرادی باشید که دارای هیچ گونه کلمه رمزی نميباشند .کلمه رمز
رمزی شده ،دومین میدان ميباشد ،بنابراين برنامه ،فقط يك طرح ميباشد :
$ awk – f : ′ $ 2 = = ″ ″ ′ / etc / passwd
طرح درخواست ميکند که آيا دومین میدان ،يك رشته خالي است ( ‘ = = ’ ،عملگر تست تساوی ميباشد) شما ميتوانید اين طرح را
به روشهای متعدد بنويسید :
″ ″==2 $ دومين ميدان خالي است
/$^/∼2 $ دومين ميدان ،رشته خالي را تطبيق ميكند
/./ ∼!2 $ دومين ميدان هيچ كاراكتري را تطبيق نميكند
= = )0length )$ 2 طول دومین میدان صفر است
علمت ، تطبيق عبارت منظم را نشان ميدهد و به ! به معناي « تطبيق نميكند» ميباشد .عبارت
منظم خودش ضميمه اسلشها ميشود.
، lengthيك عملکرد توکار از awkميباشد که طول يك رشته از کاراکترها را بوجود ميآورد .يك طرح ميتواند به دنبال ! برای
منفي کردن آن بیايد ،مانند
(! ) $ 2 = = ″ ″
‘!’ يك عملگر شبیه cميباشد ،اما برخلف sedميباشد ،چون در آنجا ! پس از طرح ميآيد.
يکي استفاده عمومي از طرحها در ، awkبرای وظايف مربوط به معتبرسازی دادههای ساده ميباشد .بسیاری از اين وظايف ،اندکي
بیشتر از جستجوی سطرهايي ميباشند که معیار خود را از دست ميدهند؛ اگر هیچ گونه خروجي وجود نداشته باشد .دادهها قابل قبول
هستندـ (هیچ خبری ،خبر خوبي نیست) .برای مثال ،طرح زير ،اطمینان ميدهد که هر رکورد ورودی که دارای تعدادی از میدانها
ميباشد ،از عملگر %برای محاسبه باقیمانده ،استفاده ميکند:
NF % 2 !=0 # print if old number of fiflds
ديگری ،سطرهای بیش از حد طولني را ،با استفاده از عملکرد lengthتوکار چاپ ميکند :
/ ength )$o( > v2 # print if too long
، awkاز همان تبديل کامنت ،همانند شل استفاده ميکند :يك . #ابتدای کامنت را علمتگذاری ميکند.
شما ميتوانید خروجي را تا حدودی آگاهي دهندهتر ،از طريق چاپ يك اخطار و بخشي از سطر بينهايت وطولني و با استفاده از يك
عملکرد توکار ديگر ، substr ،بسازيد :
length )$o( > v2 }print ″ line ″ , NR , ″too long : ″ , substr
()$o , 1 , 4
( ، s , m , n( substrرشته فرعي sرا ميسازد که در موقعیت mآغاز ميشود و nکاراکتر طولني ميباشد( .رشته در موقعیت 1آغاز
ميشود) .اگر nحذف ميشود ،رشته فرعي از mتا پايان ،استفاده ميشود ،Substr .نیز ميتواند برای استخراج میدانهای دارای موقعیت
ثابت استفاده شود ،برای مثال ،انتخاب ساعت و دقیقه از خروجي . date
$ date
Thu sep 29 12 : 17 : 01 EDT 1983
110/322 محیط برنامه سازی لینوکس
طرحهاي END , BEGIN
، awkدو طرح خاص را بوجود ميآورد،ـ BEGINوـ . ENDعملکردهایـ BEGINقبل اينکه سطر ورودی خوانده شود ،اجرا
ميشوند ؛ شما ميتوانید از طرح BEGINبرای آغاز متغیرها ،برای چاپ عنوانها و يا برای تعیین جداساز میدان با نسبت دادن آن به
متغیر FSاستفاده کنید :
$ awk { ′ BEGIN } FS = ″ : ″
> $2 = = ″ ″ ′ / etc/passwd
حساب و متغیرها
مثالهايي که تاکنون بیان شدهاند ،فقط به استفاده در متن ساده پرداختهاند .قدرت واقعي ،awkمربوط به توانايي آن برای انجام محاسبات
بر روی دادههای ورودی ميباشد ؛ شمردن چیزها ،محاسبه مجموعهها و میانگینها و مواردی از اين قبیل آسان است .يك استفاده
عمومي از ،awkجمع کردن ستون اعداد ميباشد.
برای مثال ،برای جمع کردن همه اعداد در اولین ستون :
{}s=s + $1
END { } prints
چون تعداد ارزشها در متغیر NRدر دسترس ميباشد .در نتیجه آخرين سطر را به شکل زير تغییر ميدهیم
END { } print s , s / NR
که هم مجموع و هم میانگین را چاپ ميکند.
اين مثال ،استفاده از متغیرها در awkرا نیز شرح ميدهد ، S .يك متغیر توکار نميباشد .اما از طريق استفاده شدن ،تعريف ميشود.
متغیرها بر طبق پیش فرض با صفر شروع ميشوند ،در نتیجه شما معمولً نبايد نگران آغاز باشید.
awkنیز همان عملگرهای مختصرنويسي حساب را شبیه به cفراهم ميکند ،بنابراين مثال آن در حالت عادی به اين صورت نوشته
111/322 محیط برنامه سازی لینوکس
ميشود
{} s + = $1
END { } prints
، S + = $1همانند $ + S1 = Sميباشد ،اما از نظر نمادی ،فشردهتر ميباشد .شما ميتوانید مثالي را که به شمارش سطرهای ورودی
ميپردازد مانند زير تعمیم دهید :
} nc + = length )$o( + 1 # number of chars 1 form \ n
nw + = NF # number of words
{
END { } print NR , nw , nc
اين عبارت سطرها ،کلمات و کاراکترها را در ورودی خود ميشمارد ،در نتیجه کار wcرا انجام ميدهد (اگر چه کلها را توسط فايل
تجزيه نميکند).
به عنوان مثال ديگری از حساب ،اين برنامه ،تعداد صفحات 66سطری را که با اجرای يك مجموعه از فايلها در prبوجود ميآيند،
محاسبه ميکند .چنین چیزی ميتواند در يك فرمان با عنوان ، prpagesقرار گیرد :
$ cat prpages
# prpages : compute number of pages that pr will
| * print wc $
{(awk ! / total $ / } n + = int )) $1 + 55( / 56
END } print n{′
$
pr ، ۵۶سطر از متن را در روی هر صفحه قرار ميدهد (حقیقتي که از نظر تجربي مشخص شد) .تعداد صفحات گرد ميشود ،سپس با
يك عملکرد توکار ،intبه يك عدد صحیح ،برای هر سطر از خروجي wcکه totalرا در انتهای يك سطر تطبیق نميدهد.
سر راست ميشود.
$ * wc ch 4.
753 3090 18129 ch 1.4
612 2124 13242 ch 2.4
637 2462 13455 ch 3.4
802 2986 16904 ch 4.4
50 213 117 ch 9.4
2854 11172 62847 كل
* $ prpages ch 4.
53
$
اين نتيجه pr ،را در awkمستقيما اجرا كنيد : براي
$ *pr ch 4. | awk ′ End } print NR / 66{′
53
$
متغيرها در awkنيز رشتههاي كاراكترها را ذخيره ميكنند .اينكه آيا يك متغير به عنوان يك
112/322 محیط برنامه سازی لینوکس
عدد رفتار كند و يا به عنوان يك رشته از كاراكترها ،به متن بستگي دارد براي صحبت
كردن به صورت تضميني ،در يك عبارت حسابي مانند ، S + = $1ارزش عددي ،استفاده
ميشود؛ در يك متن رشته مانندت ، x = ″abc″ارزش رشته ،استفاده ميشود؛ و در يك
مورد مبهم مانندت ، x > yارزش رشته ،استفاده ميشود مگر اينكه عملوندها به وضوح
عدديت تباشند( .قواعدت تبهت تطورت تدقيقت تدرت تكتابت تراهنمايت awkبيانت تميشوند) .متغيرهاي
رشته،ت تبراي ترشته تخالي،ت تآغازت تميشوند .آمدنت تبخشها،ت تمنجرت تبهت تاستفاده تخوبي تاز
رشتهها ميشود.
،Awkخودش شامل تعدادی از متغیرهای توکار از هر دو نوع ميباشد ،مانند NRو .FS
جدول ،۴.۳يك فهرست کامل را ارائه ميدهد .جدول ،۴.۴عملگرها را فهرست ميکند.
تمرين .۴.۸بررسي ما از ،prpagesاجراهای متناوب را بیان ميکند .بررسي کنید که کدام يك سريعترين ميباشد .
روند كنترل
به طور قابل توجهي ( با صحبت از تجربه) ،ايجاد کلمات همجوار دو نسخهای به طور تصادفي آسان است زماني که يك سند بزرگ
ويرايش ميشود و بديهي است که چنین چیزی هرگز به طور عمودی اتفاق نميافتد .برای پیشگیری از چنین مشکلتي ،يکي از اجزاء
سازنده خانواده و رك بنچ ( )workbenchاز برنامههای نويسنده با عنوان ،doubleبه دنبال جفتهايي از کلمات مشابه همجوار ميباشد.
در اينجا يك اجرا از doubleدر awkوجود دارد :
$ cat double
awk ′
FILENAME ! = prevfile } # New file
NR=1 # vesttine number
Prefile = FLIENAME
{
} NF> 0
(If )$( = = last word
Printf " double %s , file %s , line %d \ n", $1, fILENAMENR
(For )i = 2 , i < = NF, i + t
((If ) $ I = = $ ) i –1
Printf " double %s , file % s , line %d \ n " $I FLLENAME, NR
( If ) N F > 0
Lastword = $ NF
*{'$
$
عملگر ، + +عملوند خود را افزايش ميدهد و عملگر ،- -عملوند خود را کاهش ميدهد.
متغیر توکار ، FILENAMEشامل نام فايل ورودی فصلي ميباشد .چون ، NRسطرها را از آغاز ورودی ميشمارد ،در نتیجه ما آن را
در هر زماني که اسم فايل تغییر ميکند،دوباره تنظیم ميکنیم ،بنابراين ،به اين ترتیب يك سطر مزاحم به درستي شناسايي ميشود .
بیان ، ifدقیقا شبیه به بیان آن در Cميباشد:
(if )condition
113/322 محیط برنامه سازی لینوکس
statement 1
else
statement 2
اگر condilionدست باشد ،در نتیجه statement 1اجرا ميشود؛ واگر اشتباه باشد ،و اگر بخش elseوجود داشته باشد ،در نتیجه
statement 2اجرا ميشود ،بخش elseاختیاری است.
بیان ، forيك حلقه شبیه به حلقه موجود در Cميباشد ،اما متفاوت از حلقة شل ميباشد:
(fo ) expressionl , condition , expression 2
statement
، forشبیه بیان whileزير ميباشد،که در awkنیز معتبر است:
expression 1
} (while ) condition
statement
expression 2
{
براي مثال ،
)+ + for ) I = 2 , i < = NF, i
حلقه را با مجموعه iبه ترتیب ۲و … ۳تا تعداد میدانها NF،اجرا ميکند.
بیان ،breakمنجر به يك خروج سريع از forيا whileضمیمه ميشود؛ و بیان ، continueمنجر به تکرار بعدی برای شروع ميشود
همانند conditionموجود در whileو expression 2موجود در .) forبیان ، Nextمنجر به خوانده شدن سطر ورودی بعدی و
تطبیق طرح به منظور ايجاد خلصه در آغاز برنامه awkميشود .بیان exitمنجر به يك انتقال سريع به طرح ENDميشود.
آرايهها
،awkهمانند اکثر زبانهای برنامهنويسي ،آرايهها را فراهم ميکند .به عنوان يك مثال جزئي ،اين برنامه ،awkهر سطر از ورودی را در
يك عنصر آرايه مجزا جمعآوری ميکند و توسط شماره سطر شاخصبندی ميکند ،سپس آنها را در يك ترکیب معکوس پرينت
ميکند:
$ cat back words
# backwords : print in put in backward line order
{ awk ′ } line ] NR[ = $o
* END } for ) i = NR ; i > o ; i - - ( print line ] i [′ $
$
توجه داشته باشید که همانند متغیرها ،آرايهها نبايد اعلن شوند؛ اندازه يك آرايه فقط به حافظه موجود در ماشین شما محدود ميشود.
البته ،اگر يك فايل خیلي بزرگ در آرايه خوانده شود .در نهايت ممکن است از حافظه خارج شود .برای پرينت کردن انتهای يك فايل
بزرگ در يك ترتیب معکوس ،همکاری با tailلزم است :
$ tail – 5 / usr / dict / web 2 | backwards
zymurgy
zumotically
zymotic
zymothenic
zymosis
$
،tailاز مزيت يك عملکرد از سیستم فايل با عنوان ، seekingبرای پیشرفت به سمت پايان يك فايل بدون خواندن دادههای مزاحم
استفاده ميکند .به بحث و بررسي seek 1در فصل ۷مراجعه کنید ( .نسخه محلي ما از tailدارای يك انتخاب -rميباشد که سطرها
را در يك ترتیب معکوس پرينت ميکند ،به طوريکه عقب رها را جايگزين ميکند).
115/322 محیط برنامه سازی لینوکس
پردازش ورودی عادی ،هر سطر ورودی را در میدانها تقسیم ميکند .اين امکان وجود دارد که همین عملکرد تقسیم میدان را روی
هررشتهای با عملکرد توکار Splitانجام دهیم:
(n=split)s,arr,sep
رشتة nرا درون میرانهايي تقسیم ميکند که در عناصر 1تا nاز آراية arrترتیببندی ميشوند .اگر يك کاراکتر جداساز sepفراهم
شود ،استفاده ميشود ؛ در غیر اين صورت ارزش جاری Fsاستفاده ميشود .برای مثال " : "( ،و a 0$ ,( splitسطر ورودی را بر
روی «دو نقطهها» تقسیم ميکند که برای پرداش / etc/passwdمناسب ميباشد و ( " " /و dateو " ، split )" 9/29/ 83يك date
را بر روی اسلشها ،تقسیم ميکند.
$ sed 1q/etc / passwd: awk' ]split)$o,a, ":",print a ]1[ [' root
'[[$ echo 9/29/83 : awk ' ]split)$o,date," / " ( , print date ]3
83
$
جدول ،۴.۵عملکردهای توکار awkرا فهرستبندی ميکند.
جدول : ۴.۵عملکردهای توکار awk
)cos)expr کسینوس expr
) exp )pxpr تابع نمايي expr: eexpr
) ( get line سطر ورودی بعدی را ميخواند :صفر را برميگرداند اگر پايان فايل باشد
اگر پايان فايل نباشد 1 ،را بر ميگرداند
)index)s1,s2بخش صحیح expr؛ به طرف صفر سر راست موقعیت رشته S2در :s1اگر آشکار نشود صفر را بر ميگرداند
)int)expr ميکند
)length )s طول رشته s
)log )expr لگاريتم طبیعي expr
)sin )expr سینوس expr
تقسیم sبر ] [ ]n a … ]1روی کاراکتر c؛ ( s ,a,c( split nرا بر ميگرداند .
)…, sprint f)fmt فرمت … بر طبق ويژگي fmt
آرايههاي انجمني
يك مشکل استاندارد در پردازش دادهها ،جمعآوری ارزشها برای يك مجموعه از جفتهای نام /ارزش ميباشد .چنین چیزی از
ورودی به صورت زير است.
susie 400
John 100
Mary 200
Mary 300
John 100
Susie 100
Mary 100
116/322 محیط برنامه سازی لینوکس
[]sum]$1[+=$2
}]END }for )name in sum( print name , sum ]name
يك برنامه کامل برای جمع کردن و چاپ کردن مجموع جفتهای نام -ارزش همانند موارد مذکور در بال ميباشد ،حال چه آنها
ترتیب بندی شوند و چه نشوند.
هر نام ( )$1به عنوان يك زيرنويس در مجموع استفاده ميشود؛ در پايان ،يك شکل خاص از بیان ، forبرای تکرار شدن در تمام
عناصر مجموع به کار ميرود و آنها را پرينت ميکند .از نظر نحوی ،اين متغییر از بیان ، forبه اين صورت ميباشد
(For )var in array
statement
همانند حلقة forدر شل به نظر مي رسد ،اما نامربوط ميباشد .بیان forبر روی زيرنويسهای آرايه و نه بر روی اگرچه،
عناصر ،حلقهسازی ميکند و Varرا برای هر زيرنويس به ترتیب معین ميکند .زيرنويسها ،در يك ترتیب غیرقابل پیشبیني بوجود
ميآيند ،بنابراين ترتیب بندی آنها لزم است.
در مثال بال ،خروجي ميتواند درون Sortبرای فهرست کردن افراد با بزرگترين ارزشها در بال ،لولهگذاری شود.
$ awk ' …' | sort + lny
تحقق حافظه انجمني ،از يك برنامه هشزني استفاده ميکند برای اينکه اطمینان دهد که به هر عنصری با میزان زمان يکسان با عنصری
ديگر ،دستیابي ميکند و اينکه ( حداقل برای اندازههای متوسط آرايه) زمان به تعداد عناصر موجود در آرايه ،بستگي ندارد.
حافظه انجمني برای وظايفي مانند شمارش همه کلمات در ورودی مؤثر است:
$ cat word freg
{awk' }for )I=1,i <=NF, I+t(num]$I[++
{[END }for )word in num(print word , num]word
*' $
$ word freg ch40* | sort +1 -nr | sed 20q | 4
the 372 .cw 345 of 22 is 185
to 175 a 167 in 109 and 100
.p1 94 .p2 94 pp9 $87
awk87 sed 83 tha 76 for 75
The 63 are 61 line 55 print 52
$
اولین حلقه ، forبه هر کفه در سطر ورودی نگاه ميکند و عنصر آرايه زيرنويس شده numرا توسط کلمه ،افزايش ميدهد ( i$از
awkمیدن iاز سطر ورودی را با هر کدام از متغیرهای شل اشتباه نگیريد) .پس از اينکه فايل خوانده شد ،دومین حلقه ، forدر يك
ترتیب اختیاری ،کلمات و شمارههای آنها را پرينت ميکند.
117/322 محیط برنامه سازی لینوکس
تمرين ،۴.۹خروجي از word fregشامل فرمانهای فرمت کننده متن مانند cwميباشد که برای پرينت کلمات در اين فونت استفاده
مي شود .چگونه شما از مواردی که کلمه نميباشند خلص ميشويد؟ چگونه شما از trبرای انجام کار wordfregبه طور صحیح
بدون توجه به مورد ورودی آن ،استفاده ميکنید؟ تحقق و عملکرد word fregرا با خط لولهای از بخش ۴.۲و با اين مورد مقايسه
کنید:
*[→] [→] Sed' s /
/g'$*:fort | uniq –c | sort - nr
رشتهها
اگر چه sedو awkهر دو برای کارهای جزئي مانند انتخاب يك میدان تنها استفاده ميشوند ،اما awkفقط برای وظايفي که حقیقتاً
نیاز به برنامهنويسي دارند ،استفاده ميشود وتا هر میزاني قابل استفاده است .يك مثال در اين خصوص ،برنامهای است که سطرهای
طولني را تا ۸۰ستون تا ميکند .هر سطری که بیش از ۸۰کاراکتر داشته باشد پس از کاراکتر ،۸۰شکسته ميشود؛ يك \ به عنوان
يك اخطار ضمیمه ميشود و مابقي آن ادامه مي يابد .بخش نهايي يك سطر تا شده ،هم ستون شده از راست ميباشد نه هم از ستون
شده از چپ ،چون هم ستون شده از راست خروجي مناسبتری را برای صورتهای برنامه تهیه ميکند ،که اين چیزی است که ما اغلب
از fold forاستفاده ميکنیم .به عنوان يك مثال ،از سطرهای ۲۰کاراکتری بجای ۸۰کاراکتری استفاده ميکنیم و
$ cat test
A short lihe
A somewhat longer line
This line is quilte a bit/ onger than the last one.
$ fold test
A short line
\A somewat linger li
ne.
\This line is quite a
\Bit linger than the
Last one.
$
عجیب است که هفتمین ويرايش ،برنامهای را برای افزودن يا کم کردن جدول بندیها ،فراهم نميکند ،اگر prدر سیستم ، vهر دو را
انجام ميدهد .اجرای ما ا ز ، foldاز sedبرای تبديل جدول بندی ها به فاصله ها استفاده مي کند ،در نتیجه شمار کاراکتر ، awk
صحیح ميباشد ،چنین چیزی به طور صحیح برای جدولبندیهای اصلي کار ميکند ( دوباره ،نمونه مبدأ برنامه) اما ستونها را برای
جدول بندیها در وسط سطر ،حفظ نميکند.
# fold: fold long lines
sed ' /→/ [/g' $*| # converttabsto 8 spaces
'awk
}BEGIN
N=80 #folds at column 80
For )I=1, <=N,I+t( # make astring of blanks
118/322 محیط برنامه سازی لینوکس
تمرين fold ، ۴.۱۰را به گونهای تغییر دهید که سطرها را در فاصله ها يا جدولبندی ها تا کند به جای اينکه کلمه را تقسیم کند .آن را
برای کلمات طولنيتر ،به طور مطلوب بسازيد.
فرض کنید شما مي خواهید يك برنامة fieldnرا به گونهای بنويسید که میدان nام از هر سطر ورودی را پرينت کند ،بنابراين شما
برای مثال ميگوئید،
who | field $
برای اينکه فقط اسامي loginرا پرينت کنید awk .به وضوح ،توانايي انتخاب میدان را فراهم ميکند ؛ مشکل عمده عبور تعداد n
میدان در يك برنامه awkميباشد .در اينجا يك تحقق وجود دارد:
' { 'awk' }print $' $1
،$1عرضه ميشود ( درون نقل قولها نميباشد) و بنابراين عدد میداني ميشود که توسط awkمشاهده ميشود .روش ديگر ،استفاده از
نقل قولهای دوگانه ميباشد:
" { awk " }print 1 $ $ 1
در اين مورد ،آرگومان ،توسط شل تفسیر مي شود ،بنابراين 1$ ،به $تبديل ميشود و ،$1توسط ارزش nجايگزين ميشود .ما روش
نقل قول منفرد را ترجیح مي دهیم چون بسیاری از s,1اضافي با روش نقل قول دوگانه در يك برنامه نوعي awkلزم هستند.
دومین مثال addup n ،ميباشد که شمارهها رابه nامین میدان اضافه ميکند:
119/322 محیط برنامه سازی لینوکس
مثال اخیر ما از آرايههای انجمني استفاده ميکند ؛ همچنین يك شرح از چگونگي بر هم کنش با شل وجود دارد و تا حدودی در مورد
ارزيابي برنامه ،شرح ميدهد.
وظیفه ،اين است که سیستم هر روز صبح پستي را برای شما بفرستد که شامل يك تقويم از وقايع آينده باشد .ممکن است چنین
سرويس تقديمي وجود داشته باشد ؛ به )calender )1مراجعه کنید .اين بخش يك روش ديگر را نشان ميدهد).
سرويس اصلي بايد به شما وقايعي را بگويد که امروز اتفاق ميافتد ؛ دومین مرحله ،دادن يك هشدار روزانه ميباشد -وقايع فردا
همانند وقايع امروز ،استفاده صحیح از پايان هفتهها و تعطیلت به عنوان يك تمرين باقي ميماند.
اولین شرط لزم مکاني است که تقويم را نگه دارد .برای چنین کاری يك فايل با عنوان ، calender in/ usr / youآسانترين راه
ميباشد.
$ cat calender
sep 30 mother’s birthday
oct 1 1unch with joe.noon
oct 1 metting 4 pm
$
دوم ،شما نیاز به يك روش برای پويش کردن تقويم برای يك تاريخ داريد .در اينجا انتخابهای زيادی وجود دارند؛ ما از awkاستفاده
ميکنیم چون در انجام محاسبات لزم برای رفتن از امروز به فردا ،بهترين ميباشد ،اما شايد برنامهها مانند sedيا egrepنیز ميتوانند
موثر باشند .سطرهای انتخاب شده از تقويم ،توسط پست الکترونیکي ،ارائه ميشوند.
120/322 محیط برنامه سازی لینوکس
سوم اينکه ،شما نیاز به يك روش برای داشتن تقويم پويش شده به صورت قابل اعتماد و خودکار در هر روز و احتمال ً در صبح،
داريد .چنین چیزی ميتواند با atانجام شود ،چیزی که ما به طور خلصه در فصل اول ذکر کرديم .
اگر ما فرصت تقويم را محدود کنیم در نتیجه هر سطر با يك نام ماه و روز به عنوان تاريخ آغاز ميشود ،اولین نمونه برنامه تقويم آسان
است:
$ date
Thu sep 29 15:23 : 12 EDT 1983
$ cat bin / calender
# calendar:Version 1 - - today only
awk < $ HOME / calendar
{(BEGIN } split )" " \ date \ " " , date
[$ 1= = date ]2[ $ $ $2 = = date ]3
| mail $NAME
$
بلوك ، BEGINتاريخ ايجاد شده توسط dateرا در يك آرايه تقسیم ميکند؛ دومین و سومین عنصر آرايه ،ماه و روز ميباشند .ما
فرض ميکنیم که متغیر Nameاز شل ،شامل اسم loginشما ميباشد.
توالي قابل توجه کاراکترهای نقل قول ،نیازمند داشتن تاريخ در يك رشته در وسط برنامه awkميباشند .يك روش ديگر که آسانتر
ميباشد اين است که تاريخ را به عنوان اولین سطر ورودی بپذيريم:
$ cat bin / calendar
# celendar : version 2 - - today only .no quotes
| ()date , cat sHOME / calendar
' awk
NR = = 1 }mon = #2 , day = $3{# set the date
NR > 1 $ $ $1= = mon $ $ $ 2 = = day # print calendar lines
| mail $ NAME
مرحله بعدی ،مرتب کردن تقويم برای ديدن وقايع فردا همانند امروز ميباشد .اکثر اوقات ،همه آن چیزی که مورد نیاز است ،گرفتن
تاريخ امروز و اضافه کردن ۱به روز است .اما در پايان ماه ،ما بايد ماه بعد را وارد کنیم و روز را دوباره به يك برگردانیم .و البته هر
ماه دارای يك تعداد متفاوت از روزها ميباشد.
اينجا جايي است که آرايه انجمني سودمند ميباشد .دوآرايه ،Nextman ,days ،که زيرنويسهای آنها اسامي ماه هستند ،تعداد روزها
در يك ماه و نام ماه بعدی را با خود دارند .بنابراين days]" Jan" [ . 31و [" ( Jan"[ Feb,next monفوريه) ميباشد .به جای ايجاد
يك توالي کامل از بیاناتي مانند
"dsys ]" Jan"[ = 31 , next mon ]"Jan"[ = " Feb
"days ]" Feb" = 28 , nextmon ]" Feb"[ = " mar
ما از splitبرای تبديل يك ساختار مناسب از دادهها به يك ساختار حقیقت ًا مورد نیاز استفاده ميکنیم:
$ cat calendar
# calendar: version 3 - - today and tomorroew
awk <$ HOME / calendar
} BEGIN
" x = " Jan 31 Feb 28 Mar 31 Apr 30 may 31
"" Jan 31 Aug 31 sep30 oct31 nov30 Dec31 Jan 31
(split )x , data
121/322 محیط برنامه سازی لینوکس
تمرين . ۴-۱۱تقويم را به گونهای تغییر دهید که در خصوص آخر هفتهها نیز بداند .در جمعه« ،فردا» شامل شنبه ،يکشنبه و دوشنبه
ميباشد .تقويم را به گونهای تغییر دهید که به صورت پرشي از سال استفاده کند .آيا تقويم در خصوص تعطیلتها بايد چیزی ميداند؟
چگونه آن را مرتب ميکنید؟
تمرين . ۴-۱۲آيا تقويم در خصوص تاريخهای موجود در يك سطر بايد بداند ،نه فقط در آغاز سطر؟ در خصوص تاريخهای ارائه
شده در ساير فرمتها مانند ۱۰/۱/۸۳چطور؟
تمرين .۴-۱۳چرا تقويم به جای $NAMEاز getnameاستفاده نميکند؟
122/322 محیط برنامه سازی لینوکس
تمرين . ۴-۱۴يك نسخه شخصي از rmبنويسید که فايلها را وارد يك فهرست موقتي کند به جای اينکه آنها را حذف کند ،اين کار را
با يك فرمان atبرای پاك کردن فهرست انجام دهید زماني که شما خواب هستید.
پايانهاي آزاد
awkيك زبان بد ترکیب ميباشد ،ـ و نشان دادن همة تواناييهای آن در يك فصل با اندازه معقول ،غیرممکن مي باشد .در اينجا
چیزهای ديگری وجود دارند که در کتاب راهنما به آنها ميپردازيم:
۰جهت دهي خروجي printدر فايلها و لولهها :هر بیان printيا ، printfميتواند با يك > و يك اسم فايل دنبال شود ( به عنوان يك
رشته نقل قول شده يا در يك متغیر) ؛ خروجي به همان فايل فرستاده ميشود .همانند شل « << » به جای روی هم نويسي ،ضمیمه
ميشود .پرينت کردن درون يك لوله به جای > نیاز به | دارد.
۰رکوردهای چند سطری :اگر جداساز Rsرکورد ،برای سطر جديد تعیین شود ،درنتیجه رکوردهای ورودی توسط يك سطر خالي از
هم جدا ميشوند .در اين روش ،سطرهای ورودی متعددی ميتوانند به عنوان يك رکورد منفرد رفتار کنند.
«۰طرح ،طرح» به عنوان يك گزينشگر:همانند sed , edيك دامنه از سطرها ميتوانند توسط يك جفت طرح مشخص شوند .چنین
چیزی سطرها را از يك رخداد از اولین طرح تا رخداد بعدی دومین طرح ،تطبیق ميدهد .يك مثال ساده عبارت است از
NR = = 10 , NR = = 20
که سطرهای ۱۰تا ۲۰شامل را تطبیق ميکند.
اگر چه مثالهای اخیر درمورد ،awkفرمانهای خود شامل هستند ،اما اکثر استفادههای ، awkبرنامههای ساده يك سطری يا دو سطری
برای انجام پای يیدن به عنوان بخشي از يك خط لوله بزرگتر مي باشند .چنین چیزی در مورد اکثر فیلترها صحیح ميباشد -گاهي
اوقات مشکل موجود ميتواند با به کار بردن يك فیلتر تنها حل شود .اما عموماًـ ،اين مشکل به مشکلت فرعي قابل حل توسط
فیلترهای متصل شده به هم در يك خط لوله ،تجزيه ميشود .اين استفاده از ابزار اغلب به عنوان قلب محیط برنامهنويسي يونیکس ذکر
ميشود .اين نظريه ،کامل محدود کننده ميباشد؛ با اين وجود ،استفاده از فیلترها ،سیستم را گسترش ميدهد و مشاهده چگونگي
عملکرد آن ،ارزشمند است.
خروجي تهیه شده توسط برنامههای يونیکس ،ـ در يك فرمت ميباشد و به عنوان ورودی توسط ساير برنامه ها قابل درك است.
فايلهای قابل فیلتر ،شامل سطرهايي از متن ،فاقد عنوانهای تزئیني ،دنباله روها يا سطرهای فاصله ميباشند .هر سطر يك هدف از
منفعت مي باشد -يك اسم فايل ،يك کلمه ،يك توصیف از يك فرآيند اجرا -بنابراين برنامههايي مانند wcو grepميتوانند اقلم
جالب را بشمارند و يا از طريق نام در جستجوی آنها باشند .زماني که اطلعات بیشتری برای هر هدف ارائه ميشود ،فايل هنوز سطر به
سطر است ،اما درون زمینههای جدا شده توسط فاصلهها يا جدولبندیها ستون بندی ميشود ،مانند خروجي .ls-1با توجه به دادههای
تقسیم شده به چنین زمینههايي ،برنامههايي مانند awkميتوانند به آساني انتخاب شوند ،توسعه يابند و يا دوباره اطلعات را مرتب
کنند.
123/322 محیط برنامه سازی لینوکس
فیلترها ،دارای يك طرح مشترك ميباشند .هر کدام از آنها بر روی خروجي استاندارد خود ،نتیجه پردازش فايلهای آرگومان را
مينويسد و يا بر روی ورودی استاندارد ،اگر هیچ آرگوماني ارائه نشود ،آرگومانها فقط ورودیها را مشخص ميکنند و هرگز خروجي
را مشخص نميکنند ،ـ در نتیجه خروجي يك فرمان ميتواند همیشه درون يك خط لولهای پیش برود .آرگومانهای انتخابيـ ( يا
آرگومانهايي که اسم فايل نميباشد مانند طرح ، )grepقبل از اسامي فايلها قرار ميگیرند .در آخر ،پیغامهای اشتباه بر روی خطای
استاندارد نوشته ميشوند ،بنابراين ،آنها درون يك لوله ناپديد نميشوند.
اين تبديلها ،دارای اثرات اندکي بر روی فرمانهای فردی ميباشند ،اما زماني که به طور يکنواخت برای همه برنامهها بکار ميروند،
منجر به يك سهولت در امر ارتباط ميشوند ،چیزی که توسط مثالهای زيادی در سراسر اين کتاب شرح داده ميشود ،اما شايد به
طورچشمگیری ،توسط مثال شمارش کلمه در پايان بخش ۴.۲شرح داده شوند .اگر همة برنامهها خواهان يك ورودی نامگذاری شده يا
فايل خروجي باشند ،برای تشخیص پارامترها نیازمند ارتباط باشند ،و يا عنوانها و دنباله روها را بوجود آورند ،خط لولهای کار نميکند
-و البته ،اگر سیستم يونیکس لولهها را تهیه نکرده باشد ،فرد بايد يك برنامه تبديلي برای انجام اين کار بنويسید .اما لولهها وجود دارند
و خط لولهای کار ميکند و حتي نوشتن آسان است اگر شما با ابزارها آشنا باشید.
تمرين ، ps . ۴.۱۵يك عنوان توضیحي را پرينت ميکند و ls-1تعداد کل بلوکها را در فايلها اعلن ميکند .شرح دهید.
يك بررسي خوب ازطرح تطبیق کننده آلگوريتم ها ،ميتواند در مقالة « طرح در رشتهها تطبیق ميکند » نوشته ال آهو نويسندة grep
يافت شود ( .دادرسميهای سمپوزيوم در خصوص تئوری زبان رسمي به سانتا باربرا . ) ۱۹۷۹
Sedطراحي شد و توسط ال آهو ،پیتر و ينبرگر و بر اين کرنیگهان ،از طريق يك فرآيند اندکي دقیقتر ،بکار گرفته شد .نامگذاری يك
زبان پس از نويسندگان آن نیز يك کمبود خاص از تصور را نشان ميدهد .يك مقاله توسط محققان - Awkيك پويش دهي طرح و
زبان پردازش؛ نرم افزار -تجربه و عمل ،جولی ، ۱۹۷۸به بحث و بررسي در خصوص طرح ميپردازد.
، awkدر حیطههای متعدد دارای منابع خودش ميباشد ،اما مطمئنا ً عقايد خوبي را از ، SNOBOL 4از ، sedاز يك زبان معتبر
طراحي شده توسط مارك روچکايند ،از ابزار زبان lex , yaccو البته از زبان ، cبه سرقت برده است .حقیقتاً ،شباهت بین awkو < ،
منبع مشکلت ميباشدـ -زبان شبیهـ cاست اما زبانـ cنیست .برخي از ساختارها مفقود هستند؛ سايرساختارها در روشهای دقیق،
متفاوت هستند.
يك بند توسط داگ کامر ،با عنوان « سیستم فايل ثابت »FFCميباشد :
يك سیستم پايگاه دادهها شامل اصول اولیه ( نرمافزار ـ عمل و تجربه ،نوامبر ،)۱۹۸۲به بحث و بررسي در خصوص استفاده از شل و
awkبرای ايجاد يك سیستم پايگاه دادهها ميپردازد.
124/322 محیط برنامه سازی لینوکس
125/322 محیط برنامه سازی لینوکس
اعمال ماهها بصورت عدد ،ايجاد مزاحمت ميکند و هنگامي که برگردانیده شود cal 10 ،برای کل سال ۱۰ ،را چاپ ميکند ،بنابراين
بايد همواره برای مشاهدة تقويم برای يك ماه ،سال را مشخص کنید.
نکتة مهم در اينجا اين است که فرقي نميکند که فرمان calچه ارتباطي را تأمین ميکند ،ميتوانید بدون تغییر خود ، calآنرا تغییر
دهید .ميتوانید دستوری را در دايرکتوری binشخصي خود ،که يك متن مناسبتر را به آنچه calواقعي نیاز دارد تبديل ميکند ،قرار
دهید .حتي ميتوانید calنسخة خودرا بازخواني کنید که به معنای يك چیز کمتر برای يادآوری است.
اولین قضیه ،طراحي است cal :چه بايد بکند؟ اصولً calرا برای منطقي بودن نیاز داريم و بايد هر ماه را به اسم بشناسد .به دو دلیل ،
بايد همانند calقديمي عمل کند ،به جز در مورد برگرداندن نام ماهها به اعداد بنا به آرگومان يك cal ،بايد ماه يا تقويم سال را به همان
درستي چاپ کند و مطابق آرگومان صفر ،بايد تقويم جاری را چاپ کند ،چرا که اين امر ،مطمئنا ً عمدهترين استفادة فرمان است .پس
مسئله اين است که تشخیص داده شود که چند آرگومان موجود است و سپس آنها را آنگونه که calاستاندارد نیاز دارد ،مطرح کنیم.
پوسته ،يك عبارت با عنوان caseرا نیز که مناسب اتخاذ چنین تصمیمهايیست را نیز پیش رو ميگذارد:
Case word in
;; pattern( commands
;; pattern( commands
...
esac
عبارت word,caseرا با نمونه ( )patternها ،از بال تا پايین مقايسه ميکند و باعث ميشود که فرامین ،با اولین و تنها اولین نمونهای که
مطابقت کند ،همراه شوند .نمونهها با استفاده از قوانین تطابق نمونة پوسته نوشته ميشوند ،که تاحدی تعمیم يافتة آنچه ميباشند که
برای انطباق نام فايلها موجود ميباشد .هر عمل با دو ; خاتمه يافته است ;;( .ممکن است در انتهای آخرين عبارت جايگذاری شده
باشد ،اما برای ويرايش سادهتر ،معمولً آنرا داخل ميگذاريم).
نسخة calما تصمیم ميگیرد که چند آرگومان وجود دارد ،به پردازش الفبايي نام ماهها مبادرت ميکند ،سپس calواقعي را فراخواني
ميکند .متغیر پوستة ، $#تعداد آرگومانهايي را که يك فايل پوسته با آنها فراخواني ميکند ،درخود نگهداری ميکند ،ساير متغیرهای
خاص پوسته ،در جدول ۵-۱فهرست شدهاند.
$ cat cal
$ cal: nicer interface to /use/bin/cal
case $ # in
# ;; set `date` ; m=$2; y=$6هیچ آرگوماني موجود نیست :از امروز استفاده ميشود )0
# ;; m=$1; set `date`; y=$6يك آرگومان :از امسال استفاده مي شود )1
(* ;; m=$1; y=$2 دو آرگومان :ماه و سال #
esac
casc $m in
(*jan*|Jan m=1 ;;
(*feb*|Feb m=2 ;;
( * mar * | Mar m=3 ;;
(* apr * | Apr m=4 ;;
(*may * | May m=5 ;;
127/322 محیط برنامه سازی لینوکس
اولین عبارت تعداد آرگوماني را بررسي ميکند ، $ # ،و عملکرد مناسب را انتخاب ميکند .نمونة * انتهايي در caseاول : catch-all
اگر شمارة آرگومان نه صفر باشد و نه يك ،آخر عبارت اجرا خواهد شد( .از آنجايي که نمونهها به ترتیب جاروب ميشوندcatch-all ،
بايد آخرين باشد ).اين امر y,mرا برای ماه و سال انتخاب ميکند ـ دو آرگومان داده شده و calما همانند نمونة اصلي عمل خواهد
کرد.
، caseدارای يك جفت خط پیچیده شامل اولین عبارت
`Set `date
است .باوجود اينکه از ظاهر آن مشخص نیست ،اما ميتوان به سادگي با آزمايش کردن آن دريافت که اين عبارت چه عمل انجام
ميدهد:
جدول : ۵.۱متغیرهای دروني پوسته
$# تعداد آرگومانها
*$ تمامي آرگومانهايي که وارد پوسته ميشوند
@$ مشابه * $؛ بخش ۵-۷را ببینید
$- گزينههايي که برای پوسته فراهم شدهاند.
?$ مقدار بازگشتي آخرين فرمان اجراشده
$$ شناسايي فرآيند پوسته
!$ شناسايي فرآيند آخرين فرماني که با & آغاز شده
$Home آرگومان پیش فرض برای فرمان cd
$ IFS فهرست کاراکترهايي که کلمات را در آرگومانها از هم جدا ميکنند
$ MHJL فايلي که هنگام تغییريافتن ،پیغام “ ”you have mailرا فعال ميکند.
$ PATtl فهرست دايرکتوريهای جستجوی فرامین
$ PS1 رشتة فوری ،پائین فرض ''$
$ PS2 رشتة فوری برای خط فرمان ادامه دار ،پائین فرض '>'
128/322 محیط برنامه سازی لینوکس
$ date
sat oct 1 06 : 05 : 18 EDT 1983
` $ set ` date
$ echo $1
sat
$ echo $4
06 : 05 :20
$
setيك دستور دروني پوسته است که کارهای بسیاری انجام ميدهد.بدون هیچ آرگوماني ،مقدار متغیرها را درمحیط نشان ميدهد،
همانگونه که در فصل ۳ديديم .آرگومانهای متعارف ،مقادير 2$ ، $1و غیره را صفر ميکند .از اين رو 'set 'date' $را برای روز هفته
انتخاب ميکند 2$ ،را برای نام ماه و همینطور بقیه .بنابراين اولین caseدر ،calماه و سال را از تاريخ جاری تنظیم ميکند ،درصورتیکه
آرگوماني موجود نباشد؛ اگر يك آرگومان داشته باشیم به عنوان ماه در نظر گرفته ميشود و سال از تاريخ جاری استخراج ميشود.
Setهمچنین چندين گزينه را که اغلب آنها -xو -Vميباشند ،شناسايي ميکند که فرمانهای بازتابي را به موازات پیشبرد توسط پوسته،
به کار مياندازند که برای عیب يابي برنامههای پیچیدة پوسته ،حیاتي ميباشند.
مسئلهای که باقي ميماند ،برگرداندن ماه است به عدد ،اگر به فرم متني باشد .اين امر بوسیله عبارت caseدوم انجام ميگیرد که بايد
کامل ً واضح و بديهي باشد .تنها دوگانگي اين است که کاراکتر | در عبارت ، caseمانند ، egrepدللت بر يك انتخاب داردbig | :
smallمنطبق با بر bigاست يا . smallالبته اين حالتها ،بايد بصورت* ]jJ[ anيا مشابه آن نوشته شوند .برنامه اسامي ماهها را هم از
تمامي قضايای پايینتر دريافت ميکند ،چرا که بیشتر فرامین ،ورودی وضعیت پايین را قبول ميکنند ،و يا با اولین حرف بزرگ ،چرا که
dateاين ساختار را چاپ ميکند .قاعدههای تطبیق نمونههای پوسته در جدول ۵ -۲آورده شده است.
جدول : ۵-۲قوانین تطبیق نمونههای پوسته
* هر رشتهای را مطابقت ميدهد ،از جمله رشتة خنثي
? هر رشته منفرد را انطباق ميدهد
[]CCC هر کدام از کاراکترها را د cccمطابقت ميدهد.
?$ [ ]a-do-3معادل است با []abcdo123
دقیقاًـ … ـراـ ـمطابقتـ ـميدهد؛ـ ـکوتیشنها .کاراکترهایـ ـويژهـ ـراـ ـنگهـ ـميدارند،
"…"
همچنین '…'
\c Cرا جزء به جز تطبیق ميدهد.
a|b تنها در عبارات a,caseيا bرا تطبیق ميدهد
در نام فايلها ،آنهايي را که فقط با يك /در عبارات ،تطبیق داده شدهاند؛ در case
/
هرکدام که مانند ساير کاراکترها مطابقت دارند .
0 به عنوان اولین کارکتر نام يك فايل ،فقط با يك 0در عبارت تطابق دارد.
دو عبارت آخر در caseدوم ،دللت بر يك آرگومان ساده دارند که ميتواند يك سال باشد ،به خاطر بیاوريد که اولین عبارت ،case
آنرا يك ماه فرض کرده بود .اگر شمارهای باشد که بتواند نشاندهنده ماه باشد ،تنها رها ميشود ،در غیراين صورت به عنوان سال تلقي
129/322 محیط برنامه سازی لینوکس
ميشود.
سرانجام ،آخرين خط usr/bin/cal ) cal ،واقعي ) را با آرگومانهای تغییريافته ،فراخواني ميکند .نسخة calما ،به گونهای عمل ميکند
که يك تازه وارد انتظار دارد:
$ date
sat oct 1 06 : 09 : 55 EDT 1983
$ cal
october 1983
S M Tu W Th F S
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
$ cal dec
December 1983
S M Tu W Th F S
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 34
25 26 27 28 29 30 31
$
به جاي
$ 1S *.C
که بسیار ايجاد مزاحمت ميکند.
تمرين . ۵-۱اگر كاربران نسخة calشما را ترجيح دهند ،براي استفادة جهاني از آن چه
تدبيري ميانديشيد؟ براي گذاشتن آن در usr/bin/چه بايد كرد؟
تمرين . ۵-۲آيا تنظيم calبه گونهاي كه cal ۸۳تقويم ۱۹۸۳ترا چاپ كند ،ارزشمند مي
باشد؟ اگر چنين است ،تقويم ۱۹۸۳را چگونه چاپ ميكنيد؟
تمرين cal . ۵-۳را بگونهای تعريف کنید که بیتشر از يك ماه را قبول کند ،همانند:
$ cal oct nou
يا درصورت امکان تعدادی از ماهها را:
$ cal oct – dec
اگر اكنون دسامبر باشد و شمات cal janرا بخواهيد ،ژانوية سال جاري را خواهيد ديد يا
سال آينده را؟ چه زماني بايد اضافه كردن ويژگيها را به calمتوقف كنيد .
در ساختن نسخههای خصوصي از دستورهايي مانند ، calمشکلتي وجود دارد .واضحترين مشکل ،اين است که اگر با Maryکار
ميکنید و در حالي calرا تايپ کنید که با عنوان maryوارد سیستم شده باشیدcal،استاندارد را به جای نمونة جديد خواهید ديد،
البتهمگر اينکه Mary calجديد را با دايرکتوری binخود مرتبط ساخته باشد .اين امر ميتواند گمراه کننده باشد ـ به خاطر بیاوريد که
پیغامهای خطا ازـ calاصلي ،چندان مفید نميباشند ـ اما تنها ميتواند مثالي از يك مسئله کلي باشد .از آنجايي که پوسته در يك
مجموعه از دايرکتوريها که بوسیلة PATHمشخص شدهاند ،به دنبال دستورات ميگردد ،همیشه امکان اين وجود دارد که به نسخهای از
يك دستور ،غیراز آنچه انتظار داريد ،برخورد کنید .برای مثال ،اگر دستوری را تايپ کنید ،فرضا ، echoنام مسیر فايلي که واقعا ً اجرا
/ bin/echoيا چیز ديگری باشد ،که بستگي به اجزاء PATHو محل قرارگیری فايلها usr/bin/echo/0 ، ميشود ،ميتواند
دارد .وقوع يك فايل اجرايي با نام صحیح اما رفتار اشتباه غیر از آنچه انتظار داريد در جستجو ،ميتواند گمراه کننده باشد .احتمالً
معمول ترين نمونه ،دستور testميباشد که بعدا ً به آن خواهیم پرداخت :نام آن برای يك نسخة موقت برنامه ،چنان واضح است که
برنامة testاشتباه ،ميتواند بطور آزار دهندهای فراخواني شود .دستوری که گزارش دهد کدام نسخه برنامه اجرا خواهد شد ،بسیار مفید
و مورد استفاده خواهد بود.
يك شیوة اجرا ،حلقه زدن زياد دايرکتوری هايیست که در PATHنام برده شده و جستجوی هرکدام برای يك فايل قابل اجرا است که
نام آن موجود ميباشد .درفصل ، ۳از FORبرای حلقه زدن نام فايلها و آرگومانها استفاده کرديم .در اينجا ،به حلقهای نیاز داريم که
بگويد:
For iدر هر جز از PATH
do
اگر نام ارائه شده در دايرکتوری i ،موجود است.
131/322 محیط برنامه سازی لینوکس
به وضوح يك مسئله وجود دارد .يك رشتة خنثي در ،PATHمترادف است با « . » .تعويض دو نقطه با فاصله ،در ، PATHبه قدر
کافي مناسب نیست ـ اطلعات مربوط به اجزاء خنثي .از بین مي روند.
بعداً خواهیم ديد که چگونه اين مشکل را در فايلهای پوسته ،در جايي که معمولً از testاستفاده ميشود .از بین ببريم.
برای ايجاد فهرست صحیح دايرکتوريها ،بايد يك جزء بياثر از PATHرا به نقطه تبديل کنیم .جزء بياثر ،ميتواند هم در وسط و هم
در آخر رشته باشد ،از اين رو ،دستیابي به تمام حالت ،کار زيادی نميبرد:
$ echo $ PATH | sed 's/^ : / . : /
> s/^ : : / : . : /g
> s/^ : $ /: . /
> 's/^ : / /g
. / usr / you / bin / bin / usr / bin
$
ميتوانستیم آنرا بصورت چهار sedجدا از هم نوشته باشیم ،اما از آنجايي که ، sedجابهجايي را به ترتیب انجام ميدهد ،يك تقاضا
ميتواند تمامي آنها را انجام دهد.
هنگامي که اجزاء دايرکتوریـ PATHرا داشته باشیم ،دستورـ ( test)1که به آن اشاره کرديم .مي تواند اعلم کند که فايلي در هر
دايرکتوری وجود دارد .دستور testدرواقع يکي از برنامههای خام تز يونیکس ميباشد .برای مثال test-r file ،امتحان ميکند که آيا
fileوجود دارد و قابل خواندن است و test-w fileقابل نوشتن بودن را بررسيميکند ،اما ويرايش هفتم ،هیچگونه test-xرا تأمین
نميکند (باوجود اينکه سیستم Vو ساير ويرايشها تأمین ميکنند ).ما به test-fکه امتحان مي کند که فايل موجود است و دايرکتوری
نیست ،به عبارت ديگر ،يك فايل با قاعده است .به هرحال هنگامي که ويرايشهای گوناگوني موجود باشند ،برای testبايد به راهنما
مراجعه کرد.
هر دستور ،يك وضعیت خروج را برميگرداند ـ يك مقدار برای اينکه نشان دهد چه رخ داده ،به پوسته باز ميگردد .وضعیت خروج،
يك رقم کوچك است که طبق قرارداد Q ،به معنای «درست» است (دستور به درستي اجراشده) و غیر صفر به معنای «نادرست» است
132/322 محیط برنامه سازی لینوکس
(دستور با موفقیت اجرا نشده) .توجه داشته باشید که اين مقادير ،برعکس مقادير درست و نادرست در Cميباشند.
از آنجايیکه بسیاری مقادير ،ميتوانند دللت بر «نادرست» داشته باشند ،علت نقص ،اغلب در وضعیت خروج «نادرست» رمز ميشود،
grepمقدار صفر را برمي گرداند و اگر تطبیقي پیش نیايد ،يك و اگر اشتباهي در نام فايل يا برای مثال ،درصورت وجود تطابق،
نمونه باشد .۲ ،هر برنامه ،وضعیتي را برميگرداند ،هرچند معمول ً مقدار آن جالب توجه ما نیست test .در اين مورد ،غیر معمول عمل
ميکند چرا که وظیفة اصلي آن ،برگرداندن وضعیت خروج است و هیچ خروجي ايجاد نکرده و تغییری در هیچ فايلي نميدهد.
پوسته وضعیت خروج آخرين برنامه را در متغیر ? $نگهداری ميکند:
$ cmp/usr/you/ .profile / usr / you / . profile
$ هیچ خروجي :مشابهند
? $ echo $
0 Zero implies ran O.K .: files identical
$ cmp / usr /you / . profile / usr / mary /. profile
/ usr /you /.profile /usr /mary /.profile / usr / mary /. profile differ : char 6, line 3
? $ echo $
1 غیرصفر به معنای تفاوت فالهايست
$
تعدادی از دستورات مانند cmpو ، grepدارای يك گزينة Sـ ميباشند که باعث خروج آنا با يك وضعیت صحیح ميشود اما تمامي
خروجيها متوقف ميکند.
عبارت ifپوسته ،فرامیني را اجرا ميکند که براساس وضعیت خروج يك دستور ميباشند ،مانند
if دستور
then
دستور ميدهد ،اگر شرط درست باشد
else
دستور ميدهد اگر شرط نادرست باشد
fi
موقعیت خطوط جديد ،دارای اهمیت ميباشد fi ، then :و elseتنها پس از يك خط جديد يا نقطه ويرگول شناخته ميشوندelse .
اختیاری ميباشد.
جملة ، ifهمواره دستوری را اجرا ميکند ـ شرطي را ـ در حالي که جمله ، caseتطبیق نمونه را مستقیما ً درپوسته به عهده دارد.
دربرخي ويرايشهای يونیکس ،که شامل V Sysetemنیز ميباشند test ،تابعي دروني از پوسته است از اينرو ،يك ifو يك ، testبه
سرعت يكـ caseعمل ميکنند .اگرـ testدروني نباشد ،جملتـ caseکارامدتر از جملت ifميباشند و بايد برای هر نوع تطبیق
نمونهای مورد استفاده قرار گیرند:
يك دلیل برای اينکه گاهي از جملت ،caseبرای امتحان کارهايي که در پوسته بوسیلة يك جمله ifدر اغلب زبانهای برنامه نويسي
انجام ميگیرد ،وجود دارد .از طرف ديگر ،يك جملة ،caseنميتواند به سادگي تشخیص دهد که فايلي ،مقادير مجاز را خوانده باشد؛
که بهتر است بوسیله يك testو ifانجام گیرد.
از اين رو همه چیز برای اولین نخسه از فرمان ، whichسر جای خودش است؛ برای نشان دادن اينکه کدام فايل به يك دستور پاسخ
ميدهد:
$ cat which
# Which cmd : Which cmd in PATH is executed , version 1
case $ # in
0( echo 'usage : Which command' 1>&2 ; exit 2
esac
for i in ` echo $ PATH | ' s / ^ : / . : /
s / : : / : . : /g
s / :$ / : . /
` 's/:/ /g
do
if test – f $i /$1 # use test -x if you can
then
echo $i /$1
exit 0 # found it
fi
done
exit 1 # not found
$
:آنرا امتحان ميکنیم
$ cx which آنرا قابل اجرا ميکند
$ Which Which
. / Which
$ which ed
/ bin / ed
$ mv Which / usr / you / bin
$ Which Which
/ usr / you / bin / Which
$
جملة caseمبنا ،تنها بررسي خطا را به عهده دارد .به جهت يابي دوبارة 1>82در echoتوجه فرمايید ،که پیغام خطا ،مسیر را محو
134/322 محیط برنامه سازی لینوکس
نميکند ،دستور دروني پوستة ، exitميتواند به منظور برگرداندن يك وضعیت خروج مورد استفاده قرار گیرد .م ا exit 2را برای
برگرداندن يك وضعیت خطا درصورتي که دستور کار نميکرد exit 1 ،اگر نميتوانست فايل را پیدا کند و exit 0اگر يکي را پیدا
ميکرد .اگر هیچ جملة exitصريحي وجود نداشته باشد ،وضعیت خروج از فايل پوسته ،وضعیت آخرين دستور اجرا شده است.
چه اتفاقي رخ ميدهد اگر برنامهای داشته باشید که نام آن در دايرکتوری جاری testباشد؟
(فرض ميکنیم که testدستور دروني از پوسته نیست).
يك Testحلقه ايجاد ميکند .آنرا قابل اجرا ميکند.
$ echo 'echo hello′ >test
$ cx test آنرا قابل اجرا مي کند
را امتحان مي کند Whichحال Which Which $
hello مردود مي شود !
. /Which
$
بررسي خطای بیشتری فراخواني ميشود .ميتوانستیدـ whichرا به منظور يافتن نام کامل مسیر برایـ testاجرا کنیدـ (اگرـ testدر
دايرکتوری جاری نبود) ،و آنرا صراحتاً مشخص کنید .اما قانع کننده نیست test :ممکن است در دايرکتوریهای مختلف در سیستمهای
مختلفي باشد و whichنیز بستگي به echoو sedدارد ،از اين رو بايد نام مسیرهای آنها را نیز مشخص کنیم .يك راه حل سادهتر
وجود دارد PATH :را در فايل پوسته تنظیم کنید ،تا فقط در bin /و usr/bin/برای دستورات باشد .البته ،تنها برای دستور ،which
مجبور به ذخیرة PATHپیشین برای تعیین توالي دايرکتوریهايي که بايد جستجو شوند ميباشید.
$ cat which
# Which cmd : Which cmd in PATH is executed , final version
opath = $ PATH
PATH = / bin : / usr / bin
case $ # in
(0 echo ' Usage : Which command ' 1 > & 2 ; exit 2
esac
for i in ` echo $ opath | sed 's / ^ : / . : /
s/::/:.:/g
s/:$/:./
` 's / : / /g
do
if test – f $ i / $1 # this is / bin / test
then # or / usr / bin / test only
echo $i / $1
exit 0 # found it
fi
done
exit 1 # not found
$
135/322 محیط برنامه سازی لینوکس
اکنون whichحتي اگر يك ( Testيا sedيا ) echoجعلي نیز در خلل جستجو وجود داشته باشد ،عمل مي کند.
$ 1S – 1 test
rwxrwxrwx 1 you 11 oct 1 06:55 test still there
$ which which
/ usr / you / bin / which
$ which test
. / test
$ rm test
$ which test
/ bin / test
$
پوسته دو عملگر ديگر را نیز برای ترکیب فرامین ،تأمین ميکند ¦¦ ،و && ،که اغلب فشردهتر و راحتتر از جملة ifميباشند .برای
مثال ¦¦ ميتواند برخي جملت ifرا جابجا ميکند:
dose not existنام فايل ¦¦ echo fileنام فايل test - fمعادل است با:
نام فايل if test ! – f ! شرط را منفي ميکند.
then
echo file filename dose not exist
fi
عملگر ¦¦ ،علي رقم ظاهر آن ،هیچ ربطي به لولهها ندارد ـ عملگری است شرطي به معنای . OR
دستور سمت چپ ¦¦ به اجرا درخواهد آمد .اگر وضعیت خروج آن ،صفر باشد( ،موفقیت) ،دستور سمت راست ¦¦ ناديده گرفته ميشود.
اگر سمت چپ ،مقداری غیر صفر را برگرداند (عیب) سمت راست اجرا شده و مقدار کل عبارت ،وضعیت خروج سمت راستي خواهد
بود .به عبارت ديگر ¦¦ ،يك عملگر ORشرطي است که دستور سمت راست خود را در صورت موفقیت سمت چپ ،اجرا نميکند.
&& شرطي پاسخ AND ،ميباشد؛ دستور سمت راست خود را خود را تنها هنگامي اجرا ميکند که سمت چپي موفقیت آمیز باشد.
تمرين . ۵-۴چرا PATH Whichرا به ،Opathقبل از خروج مقدار دهي اولیه نميکند؟
تمرين . ۵-۵از آنجائیکه پوسته از esacبرای پايان دادن به يك caseاستفاده ميکندو از fiبرای اتمام يك ، ifچرا از doneبرای اتمام
doاستفاده ميکند؟
تمرين . ۵-۶يك گزينه aـ را به whichاضافه کنید.بگونهای که تمامي فايلها را در PATHچاپ کند به جای اينکه بعد از اولین فايل،
خارج شود .راهنماييmatch=´exit O´ . :
تمرين Which . ۵-۷را بگونهای تعريف کنید که فرامین درون پوسته مانند exitرا بشناسد.
تمرين Which. ۵-۸را بگونه ای تعريف کنید که مجاز بودن اجرا را روی فايلها بررسي کند .آنرا جهت چاپ يك پیغام خطا هنگام
نیافتن يك فايل ،تغییر دهید.
136/322 محیط برنامه سازی لینوکس
در فصل سوم ،از حلقه forبرای برخي برنامههای تبادلي ساده استفاده ميشود .معمولً Forحول مجموعهای از نام فايلها حلقه ميزند،
مانند ' ً For i in *.cيا هر برهاني در برنامه پوسته همانند' * . 'i in For $اما حلقهةای پوسته کلي تر از اين تعابیر هستند؛ حلقة forرا
در Whichدر نظر آوريد.
سه نوع حلق وجود دارد for . until , while , for :دارای بیشترين استفاده است و مجموعه ای از دستورات را اجرا ميکند – بدنة
حلقه ـ يکبار برای هر عضوی از مجموعه کلمات که اغلب آنها نام فايلهاست.
Until – whileوضعیت خروج را از يك دستور ،برای کنترل اجرای دستورات بدنه حلقه به کار ميبرد.
بدنة حلقه تا هنگامي اجرا ميشود که دستور شرط ،يك مقدار غیر صفر را (برای ) whileيا صفر (برای ) unitباز گرداند While .و
، unitمگر برای تفسیر وضعیت خروج دستور ،قابل تشخیص ميباشند.
در اينجا فرم پاية هر حلقه آورده شده است:
for I in فهرست کلمات
do
تنظیم از روی عناصر متوالي فهرست ، $iبدنه حلقه
done
(فهرست ،تمامي آرگومانهای فايل پوسته است ،برای مثال for i ) * $ ،
do
بدنه حلقه i $ ،به آرگومانهای متوالي تنظیم مي شود.
Done
دستور While
do
بدنه حلقهها را که دستور مقدار درست را بر ميگرداند اجرا ميشود.
Done
دستور until
do
بدنه حلقه تا جايي که دستور مقدار نادرست را بر ميگرداند ،اجرا ميشود
Done
دومین فرم forکه در آن يك فهرست خالي ،دللت بر * $ميکند ،خلصه نويسي است برای بسیاری استفادههای معمول .دستور
شرطي که whileيا untilرا کنترل ميکند ،ميتواند هر دستوری باشد .يك مثال جزيي ،حلقة Loopاست که منتظر ميماند تا کسي
وارد سیستم شود (:)Mary
While sleep 60
do
Who | grep mary
dcne
Sleepكه توقفي 60ثانيه ايجاد ميكند ،در حالت عادي همواره اجرا ميشود (مگر اينكه
137/322 محیط برنامه سازی لینوکس
قطع گردد) و از اين روت «موفقيت» را بر ميگرداند ،ت سپس حلقه هر يك دقيقه يك بار
بررسي ميكند كه آيا Maryوارد شده يا نه.
اين نسخه داراي اين نقص ميباشد كه اگر Maryدر حال حاضر وارد شده باشد ،بايد 60
محتويات حلقه را ميتوان بيرون آورده و با untilنوشت تا اطلعات را يكبار و بدون تأخير
تأمين كرد ،اگر maryاكنون وارد شده باشد:
until who ¦ grep mary
do
sleep 60
done
اين شرط ،جالبتر ميباشد ،اگر Maryوارد شده باشد ’who |grep mary’ ،مشخصات ورود او را در فهرست بندی whoچاپ کرده
و ً درست ً را بر ميگرداند ،چراکه grepيك وضعیت را جهت نشان دادن اين که چیزی را يافته ،بر ميگرداند.
سرانجام ،اين دستور را پوشش داده ،به آن اسمي ميدهیم و آنرا نصب ميکنیم.
$ cat watchfor
# watchfor : watch for sommeone to log in
PATH = / bin : / usr / bin
case $ # in
(0 echo ' Usage : watchfor person' 1 > &2 ; exit 1
esac
'' until who \ egrep '' $ 1
do
sleep 60
done
$ cx watchfor
$ watchfor you
you ttyo کار مي کند oct 1 08:01
$ mv watchfor / usr / you / bin آنرا نصب مي کند
$
grepرا با egrepتعويض کرديم ،پس ميتوان نوشت ´watch for ´joe | mary $ :تا ورود بیشتر از يك نفر را کنترل کند.
به عنوان يك مثال پیچیدهتر ،ورود و خروج تمامي افراد را زير نظر ميگیريم وهر گاه افرادی وارد يا خارج شوند ،گزارشي ارائه مي
دهیم -نوعي whoافزايشي ،ساختار پاية آن ،ساده است :هر يك دقیقه who،اجرا مي شود ،خروجي آن با يك دقیقه قبل مقايسه مي
شود و هر گونه اختلفي ،گزارش مي شود .خروجي ، Whoدر يك فايل نگهداری ميشود تا بتوان آنرا در دايرکتوری / tmpذخیره
کرد .برای تشخیص فايلهای خود از فايلهای مربوط به ساير پردازشها ،متغیر پوسته ( $$شناسة پردازش دستور پوسته) با نام فايل ترکیب
138/322 محیط برنامه سازی لینوکس
ميشود که قراردادی متداول است .رمز کردن نام دستور در فايلهای موقتي ،اکثرا ً برای مدير سیستم انجام ميپذيرد .دستورات ( شامل
اين نسخه از ) watch whoاغلب فايلها را در ،/tmpرها ميکند و جالب است بدانید که کدام دستور اين کار را انجام ميدهد .
$ cat watch who
# watchwho : watch who logs in and out
" ":يك دستور درون پوسته است که کاری به جز نشان دادن برهانهای خود و برگرداندنـ " درست" انجام نميدهد .در عوض،
ميتوانستیم از دستور trueکه خود يك وضعیت خروج صحیح را بر ميگرداند استفاده کنیم( ،همچنین يك دستور falseنیز وجود
دارد) .اما " ":مؤثرتر از trueاست چرا که دستور را از سیستم فايل اجرا نميکند.
خروجي ، diffاز > و < برای تشخیص دادهها از دو فايل استفاده ميکند .برنامه awkاين مورد را برای گزارش تغییرات بصورتي
بسیار ساده برای يادگیری ،پردازش ميکند .توجه کنید که کل حلقه ، whileبه awkمرتبط است ،به جای اينکه يك awkتازه را هر
از يك دقیقه اجرا کند Sed .برای اين پردازش مناسب نميباشد ،چرا که خروجي آن همواره عقب تر از ورودی آن در يك خط است:
همواره يك خط ورودی وجود دارد که پردازش ميشود اما چاپ نميشود ،و اين امر باعث تأخیری ناخواسته ميگردد.
به دلیل اينکه oldخالي ايجاد شده است،اولین خروجي از ، Watchwhoفهرستي از تمامي کار براني است که در حال حاضر وارد
شدهاند .تغییر دادن دستوری که oldرا ميسازد ،به ،who > $oldباعث ميشود Watchwho .تنها تغییرات را چاپ کند؛ که امری
است اختیاری.
يك برنامة حلقة ديگر ،برنامهايست که متناوبا ً به mailboxشما نگاه ميکند؛ هر گاه تییر کند ،برنامه “ ''You have mailرا چاپ
ميکند که جايگزيني است مناسب برای مکانیزم دروني پوسته که از متغیر MAILاستفاده ميکند .ما آنرا با متغیرهای پوسته به جای
فايلها به کار گرفتیم ،تا راهي متفاوت برای انجام کارها را نشان دهیم.
$ cat checkmail
# checkmail : watch mailbox for growth
PATH = / bin : / usr / bin
MAIL = / uar / spool / mail / `getname ` # system dependent
{ t = $ } 1 – 60
'' ` x= '' ` 1s – 1 $ MAIL
while :
do
139/322 محیط برنامه سازی لینوکس
دوباره از ، awkاينبار برای اطمینان از اينکه پیغام تنها هنگامي که mail boxزياد شود چاپ شود و نه هنگامي که تنها تغییر کند،
استفاده کرديم .در غیر اين صورت ،دقیقا ً بعد از حذف يك ، mailپیغامي مشاهده خواهید نمود( .ويرايش دروني پوسته از اين نقطه،
دارای ضعف است).
ساعت دروني ،به طور معمول روی 60ثانیه تنظیم شده ،اما اگر پارامتری در خط دستور باشد ،مانند:
cat checkmail 30 $
اين زمان به جای قبلي استفاده ميشود .متغیر پوسته ، tدر صورتي زماني اعمال شود ،مقدار آنرا ميگیرد و اگر مقداری داده نشود،
همان 60را از خط :
} t = $ } 1 – 60
ميگیرد .اين موضوع ،ويژگي ديگری از پوسته را معرفي ميکند.
{ $}varمعادل است با $ varو ميتواند جهت صرف نظر کردن از مسائل ناشي از متغیرهای درون رشتههای شامل حروف يا اعداد،
به کار رود:
$ var = hello
$ varx=goodbye
$ echo $ var
hello
$ echo $ varx
goodbye
$ echo $ }var {x
hellox
$
کاراکترهای خاص درون براکتها ،پردازش ويژه متغیرها را مشخص ميکند .اگر متغیر تعريف نشده باشد و در پي نام آن علمت سؤال
آمده باشد ،رشتة بعد از ؟ چاپ ميشود و پوسته خارج ميشود (مگر اينکه تباد لي باشد) .اگر پیغام خاصي مهیا نشده باشد،استاندارد
آن بصورت زير چاپ ميشود:
$ echo {? $ }var
hello O.K.;var is set
{?$ echo $ } junl
junk : parameter not set پیغام پیش فرض
{ !$ echo $ } junk?error
! junk : error پیغام اعمال شده
$
توجه داشته باشید که پیغامي که توسط پوسته ساخته ميشود ،همواره شامل نام متغیر تعريف نشده است.
140/322 محیط برنامه سازی لینوکس
يك فرم ديگر $ }Var-thing { ،ميباشد که آنرا با $ Varارزيابي ميکند ،اگر تعريف شده باشد و با ، thingاگر تعريف شده نباشد.
{ $ }Var = thingنیز مشابه است ،اما thingرا نیز با $ Varمقدار دهي ميکند:
{ ' $ echo $ }junk- 'Hi there
{?Hi echo $ }junk
junk : parameter not set junkتأثیر نپذيرفته است
{' $ echo $ } junk= 'Hi there
Hi there
{ ?$ echo $ } junk
Hi there Hi , junkمقدار دهي شده
$
$ }Var+thing{$
اگر تعريف شده باشد . $ Var ،در غیر اين صورت message ،را چاپ کرده و از
پوسته خارج ميشود .اگر messageخالي باشد ،چاپ ميکندVar: parameter :
not set
اگر $ Varتعريف شده باشد thing ،و در غیر اين صورت هیچ چیز
تمرين .۵-۹به کاربرد trueو Falseدر bin /يا user /bin /توجه کنید .چگونه ميتوانید متوجه شويد چگونه کار ميکنند؟
تمرين Water for . ۵-۱۰را بگونهای تغییر دهید که برهانهای گوناگوني به عنوان افراد تلقي گردند ،به جای اينکه نیاز باشد کاربر ´Joe
´| maryرا تايپ کند.
تمرين . ۵-۱۱نسخهای از watchwhoبنويسید که از Commبه جای awkبرای مقايسه دادههای جديد و قديمي استفاده کند.
تمرين .۵-۱۲نسخهای Watchwhoبنويسید که خروجي whoرا به جای فايلها ،در متغیرهای پوسته ذخیره کند .کدام نسخه را ترجیح
141/322 محیط برنامه سازی لینوکس
ميدهید؟ کدامیك سريعتر اجرا ميشود؟ آيا Watchwhoو ، Checkmailبايد & را به صورت خودکار انجام دهند؟
تمرين .۵-۱۳چه تفاوتي میان دستور do-nothingو کارکتر #درپوسته وجود دارد؟ آيا هر دو مورد نیاز هستند؟
اگرـ DELرا فشار دهید يا هنگام اجرایـ ، watchwhoگوشي تلفن را بگذاريد ،يك يا دو فايل موقت ،درـ / tmpباقي ميماند.
Watchwhoبايد آنها را قبل از خروج حذف کند و بايد راهي برای رويايي چنین حالتي و بازيافت آنها ،بیابیم.
هنگامي که DELرا تايپ ميکنید ،يك سیگنال وقفه به تمام پردازشهای در حال اجرا در ترمینال ،ارسال ميشود .مشابهاً ،هنگامي که
گوشي را ميگذاريد يك سیگنال hang upفرستاده ميشود .سیگنالهای ديگری نیز وجود دارند .اگر برنامهای ،عملي واضح را در مورد
سیگنالها به کار نبندد ،سیگنال آنرا به اتمام ميرساند .پوسته برنامههايي که با & اجرا مي شوند را از وقفهها محافظت ميکند اما از تعلیق
نه.
فصل هفتم سیگنالها را مفصل به بحث ميگذارد ،اما نیازی به شناختن زياد آنها برای به کار بستنشان در پوسته نیست.
فرمان دروني پوسته ، Trapرشتهای از دستورها را هنگامي که سیگنال واقع ميشود ،جهت اجرا ميچیند:
رشتهای از دستورات trap فهرستي از شمارههای سیگنال
رشتهاي از دستورات ،آرگوماني منفرد است ،از اين رو بايد تقريباً هميشه داخل كوتيشن قرار گيرد.
شمارههاي سيگنال ،ارقام كوچكی هستند كه سيگنال را معرفي ميكنند .براي مثال ۲ ،سيگنالي
است كه بواسطة فشردن كليد DELبوجود ميآيد .و ۱بواسطة گذاشتن گوشي ،بيشتر شمارههاي
سيگنال مفيد براي برنامهنويسان پوسته در جدول ۵-۴آمدهاند.
...
رشته دستوری که اولین آرگومان را برای Trapشکل ميدهد ،مانند فراخواني يك زير روال است که بلفاصله هنگامي که سیگنال واقع
ميشود ،رخ ميدهد .هنگامي که به اتمام رسید،برنامهای که در حال اجرا بوده ،همانجايي که بوده را از سر ميگیرد ،مگر اين که سیگنال
آنرا از بین ببرد .بنابراين ،رشته دستوری ، trapبايد صراحت ًا exitرا احضار کند ،يا برنامه پوسته اجرا را پس از وقفه ،ادامه خواهد داد.
همچنین رشته دستوری ،دوباره خوانده خواهد شد :يکبار هنگام مقدار دهي trapو يکبار هنگام احضار آن .از اين رو رشتة دستوری به
بهترين نحو با کوتیشن محافظت شده ،متغیرها فقط هنگام اجرای روالهای Trapارزيابي ميشوند که در اين حالت هیچ تفاوتي
نميکند اما به يك مورد بر خواهیم خورد که تفاوت خواهد داشت .به هر حال ،گزينة - fبه rmميگويد که سؤالي نپرسد.
Trapگاهي از نظر تبادلي مفید ميباشد ،اغلب جهت جلوگیری از بین رفتن يك برنامه بوسیله سیگنال تعلیق ايجاد شده توسط يك
تلفن شکسته:
& ( $ ) trap ' ' 1; long-running- command
2134
$
رشتة دستوری خنثي به معنای « صرف نظر از وقفهها » در اين فرآيند ميباشد .پرانتزها باعث اجرای همزمان trapو دستور در يك
زير پوستة زمینه ميشود؛ بدون آنها trapبرای پوسته ، loginهمانند long-ranning-commanبه کار بسته خواهد شد.
فرمان ( nohup )1برنامهای کوتاه از پوسته است جهت جلوگیری از اين عمل.
در اينجا نسخه ويرايش هفتم آمده شده است:
` $ cat `which nohup
trap '' '' 1 15
if test -t 2> &1
then
'' ' echo '' sending output to ' nohup . out
exec nice -5 $ * >>nohup.out 2>&1
else
exec nice -5 $ * 2>&1
fi
$
Test-tامتحان ميکند که خروجي استاندارد ،يك ترمینال است ،تا آنرا ذخیره کند .برنامة زمینه ،بوسیله niceاجرا ميشود تا اولويتي
پايینتر از برنامه های تبادلي به آن دهد( .توجه داشته باشید که nohupبه PATHمقدار دهي نميکند .آيا بايد بدهد؟)
execفقط برای کارآيي است؛ دستور به تنهايي و بدون آن نیز به خوبي اجرا ميشود exec .دستوری دروني از پوسته است که فرآيند
در حال اجرا در اين پوسته با برنامهای که نام آن آورده ميشود ،عوض ميکند ،بدين وسیله يك فرآيند را ذخیره مي نمايد ـ پوستهای
که در حالت عادی منتظر ميماند تا برنامه تکمیل شود .ميتوانستیم از execدر جاهای مختلفي استفاده کنیم ،مانند انتهای برنامه cal
ارتقاء يافته ،هنگامي که / usr/bin/binرا احضار ميکند.
سیگنال ، ۹سیگنالي است که نميتوان آن را صرف نظر کرد يا بدست گرفت :همواره از بین ميرود ،از پوسته ،بدين گونه ارسال
143/322 محیط برنامه سازی لینوکس
ميشود:
$ Kill – 9 . . .عنوان فرآيند
kill -9 is not the default becaise a process killed that way is given no chance to put its affairs in order
before dying.
پیش فرض نیست Kill-a
تمرين . ۵-۱۴نسخه باليي ، nohupخطای استاندارد دستور را با خروجي استاندارد ترکیب ميکند .آيا اين طرح ،مناسب است؟ اگر
نه ،چگونه آن رابه خوبي از هم جدا ميکنید؟
تمرين . ۵-۱۵دستور درون پوستة timesرا پیدا کنید و به profileخود خطي اضافه کنید به گونهای که هر گاه از پوسته خارج شويد،
مدت زمان استفاده شما از CPUچاپ شود.
تمرين . ۵-۱۶برنامه ای بنويسید که مشخصات کاربر قابل دسترس بعدی رادر etc/passwdپیدا کند .اگر مشتاق هستید ( واجازه
داريد) ،آنرا به دستوری اعمال کنید که کاربری جديد را به سیستم اضافه کند .چه مجوزهايي نیاز دارد؟ چگونه بايد با وقفهها برخورد
کند؟
تعريف چنین دستورهايي جهت افزودن گزينه ،غیر عملي خواهد بود .علوه بر اينکه ،طرحي بد خواهد بود :بهتر است که توابع را هم
مرکز کنیم ،همانگونه که پوسته با عملگر > انجام ميدهد .برای اين کار Overwrite ،را برای برنامه به کار ميبريم .اولین طرح مشابه
زير است:
sed 's / UNIX/UNIX)TM( / g' ch2 | overwrite ch2 $
اين اشارة ابتدايي ،قابل فهم است – فقط ورودی را تا انتهای فايل جايي ذخیره کنید و سپس دادهها را روی فايل آرگومان ذخیره کنید:
# overwrite : copy standard input to output aftert EOF
# version 1. BUG here
PATH= /bin:/usr/bin
case $# in
(1 ;;
( • ;echo 'Usage : overwrite file' 1>&2 exit 2
esac
new= /tmp/overwr . $$
trap ' rm -f $ new ; exit 1' 1 2 15
144/322 محیط برنامه سازی لینوکس
اگر پیش از دستیابي به فايل اصلي ،يك DELرخ ميدهد ،فايلهای موقتي حذف شده و فايل تنها رها ميشود .پس از ساختن پشتیبان،
سیگنالها صرف نظر ميشوند بطوريکه CPبا وقفه ،متوقف نميگردد ـ هنگامي که CPشروع شود Overwrite ،مجبور به تغییر فايل
اصلي ميشود.
هنوز يك مسئله ريز وجود دارد .توجه کنید:
$ sed 's/UNIX/UNIX)TM(g' percious | overwrite precious
command garbled : s/UNIX/UNIX)TM( g
$ 1s -1 precious
-rw-rw-rw- 1you 0 oct 1 09:02 precious !*@# $%
$
اگر برنامهای که ورودی را برای Overwriteمهیا ميکند ،دچار اشتباه شود ،خروجي آن خالي خواهد بود و Overwriteبنا به وظیفه و
به لحاظ اطمینان ،فايل آرگومان را از بین ميبرد.
چند راه حل ممکن به نظر مي رسد Overwrite .پیش از جابجايي فايل ،منتظر تأيید ميتواند باشد ،اما تبادلي کردن آن ،شايستگي آن را
ميکاهد Overwrie .ميتواند بررسي کند که ورودی فايل خالي نباشد (بوسیلة ) Test-zاما اين کار نیز صحیح نیست :چند خروجي
ممکن است ايجاد شود پیش از آنکه خطا رديابي شود.
بهترين راه حل ،اجرای برنامة تولید داده ،تحت کنترل Overwriteاست تا حالت خروج آن قابل بررسي باشد ،که خلف روال مرسوم
145/322 محیط برنامه سازی لینوکس
: بي سابقه نیست، هیچ کلیاتي از بین نمي رود و متن آن، با اين حال، ايجاد نميکند، هیچ چیزی در خروجي خودOverwrite ،است
. همگي دستوراتي هستند که دستور ديگری را به عنوان آرگومان مي پذيرندnohup وtime ، nice
:نسخة صحیح در اينجا آمده است
# Overwrite : copy standard input to output after EOF
# final version
opath=$ PATH
PATH=/bin:/usr/bin
case $# in
0 | 1 ( echo `Usage: overwrite file cmd ]args[' 1>&2; exit 2
esac
file=$1; shift
new=/tmp/overwr 1 . $$; old=/tmp/overwr2.$$
trap 'rm -f $new $old; $old; exit 1' 1 2 15 # clean up fikes
if PATH=$opath ''$@'' >$new # collect input
then
cp $file $old # save original file
trap ' ' 1 2 15 # we are committed; ignore signals
cp $ new $file
else
echo ''overwite : $1 failed ,$ fild unchanged'' 1>&2
exit 1
fi
rm -f $new $old
@ $" . و غیره$2 ميشود$3 . $1 ميشود$2 : کل فهرست آرگومان را يکي به چپ منتقل ميکند، Shift فرمان درون پوستهای
. دوباره به آن خواهیم پرداخت5-7 در بخش. اما وقفه نميپذيرد، تأمین ميکند،$* مانند،)" تمامي آرگومانها را (پس از انتقال
، نبودندusr/bin/ ياbin/ دستوراتي که در، برای اجرای دستورات کاربر بازخواني ميشود؛ اگر چنین نبودPATH توجه داشته باشید که
. غیر قابل دسترس مي بودندOverwrite برای
Overwrite now works )if somewhat clumsily(:
اکنون عمل مي کند
$ cat notice
UNIX is a Trademark of Bell laboratories
$ overwrite notice sed 's/UNIXUNIX)TM( /g' notice
command garbled: s/ UNIXUNIX)TM(/g
overwrite : sed failed, notice unchanged
$ cat notice
UNIX is a Trademark of Bell Laboratories Unehanged
$ overwrit notice sed 's /UNIX/UNIX)TM(/g' notice
$ cat notice
UNIX )TM( is a Trademark of Bell Laboratorise
$
146/322 محیط برنامه سازی لینوکس
استفاده از Sedبرای جابجايي تمام رخدادهای يك کلمه ،با يکي ديگر ،عملکردی معمولي است .با داشتن ،Overwriteخودکار کردن
اين وظیفه آسان است:
$ cat replace
# replace: replace str1 in files with str2, in place
PATH = /bin:/usr/bin
case $# in
0 | 1 | 2 ( echo ' Usage: replace str1 str2 files ' 1>&2; exit 1
esac
left = '' $1 '' ; right = ''$2''; shift; shift
for i
do
overwite $i sed ''s@$ Left@$right@g'' $i
done
$ cat footnote
UNIX is not an acronym
$ replace UNIX Unix footnote
$ cat footnote
Unix is not an acronym
$
( به خاطر بیاوريد که اگر فهرست در يك عبارت forخالي باشد ،پیش فرض آن* $ميشود ).ما از @ به جای /برای محدود کردن
دستور جابجايي استفاده کرديم ،چرا که @ کمتر با يك رشتة ورودی اشتباه گرفته مي
22126شود.
replace ، PATHرا از bin:/ust/bin/مقدار دهي ميکند.
اين بدان معني است که Ovewriteبايد برای عمل کردن ، replaceدر usr/bin /باشد .اين فرض را برای ساده شدن کار در نظر
گرفتیم .اگر نميتوانید overwriteرا در usr / bin /نصب کنید ،مجبور به گذاشتن HOME/bin $در PATHدرون replaceهستید
يا نام مسیر overwriteرا صراحت ًا وارد کنید .از اين به بعد فرض مي کنیم.
تمرين . ۵-۱۷چراـ ، overwriteاز کد سیگنالـ Oدرـ trapاستفاده نميکند که فايلها هنگام خروج ،حذف شوند؟ راهنمايي :هنگام
اجرای برنامه زير DEL ،را تايپ کنید:
trap '' echo exiting; exit 1'' 0 2
Sleep 10
. ۵-۱۸يكـ ـگزينه ـ -Vراـ ـبه ـ replaceاضافهـ ـکنیدـ ـتاـ ـتماميـ ـخطوطـ ـتغییرـ ـيافتهـ ـدر ـ deu/tty/راچاپـ ـکند .راهنمايي:
S/$/sedt/$right/gsuflog
Replace . ۵-۱۹را به گونهای تنظیم کنید که بدون توجه به کاراکترها در جابجايي رشتهها عمل کند .
. ۵-۲۰آيا replaceرا ميتوان برای عوض کردن متغیر iبا indexدر هر کجای برنامه استفاده کرد؟ برای انجام چنین موردی ،چه
چیزهايي را ميتوانید تغییر دهید؟
. ۵-۲۱آيا replaceبه مقدار کافي توانمند مي باشد که به usr/bin/تعلق داشته باشد .آيا وارد کردن دستورات ، sedهنگام نیاز ،ساده
147/322 محیط برنامه سازی لینوکس
ميباشد؟
( . ۵-۲۲مشكل) $ overwrite file ′who | sort ′
عمل نميکند .توضیح دهید چرا و آنها را تصحیح کنید .راهنمايي eval)1(:را در( sh )1ببینید .راه حل شما ،چگونه بر تفسیر
متاکاراکترها در دستور تأثیر ميگذارد.
دستور kilفقط فرآيندهايي رابه پايان مي رساند که بوسیلة شناسة فرآيند ،معرفي شده باشند .هنگامي که يك فرآيند زمینة خاص ،لزم
به از بین رفتن است،معمولً بايد PSرا برای يافتن شناسة فرآيند اجرا کرد و سپس به دشواری آنرا مانند يك آرگومان دوباره وارد کرد
تا از بین روند .اما وارد کردن برنامه برای چاپ عددی که فورا ً آنرا بطور دستي رونويسي ميکنید ،چندان عاقلنه نیست .چرا برنامهای
ننويسیم ،مثلً با sayکه اين کار را خودکار انجام دهد؟
يك دلیل اين است که فرآيندهای از بین برنده ،خطرناك مي باشند و بايد مراقب بود که فرآيند صحیح از بین برود .يك روش سالم و
مناسب ،اجرا کردن ZAPاست بصورت تبادلي ،و استفاده از Pickبرای انتخاب قربانيها.
يك يادآوری سريع دربارة :Pickهر کدام از آرگومانهای خود را به نوبت چاپ کرده و از کاربر پاسخ ميخواهد؛ اگر پاسخ yباشد،
آرگومان چاپ مي گردد Pick( .موضوع بخش بعدی است)
ZAPاز Pickاستفاده ميکنند تا صحت فرآيندهايي را که از روی نامشان توسط کاربر ،برای از بین رفتن انتخاب شدهاند را بررسي
کند.
$ cat zap
# zap pattetn: kill all ptocesses matching pattern
# BUG in this vetsion
PATH=/bin : /usr/bin
cas $# in
(0 ecvgo 'Usage: zap pattern' 1>&2; exit 1
esac
` ' {!kill `pick \ `ps – sg | frep '' $* ''\ ` | awk ' }print $
$
.1به علمتهای ` که توسط backslashها احاطه شده اند ،توجه کنید .برنامة ، awkشناسه فرايند را از خروجي PSکه بوسیلة Pick
انتخاب شده ،بر ميگزيند:
& 4 sleep 1000
22126
$ ps – ag
PID TTY TIME CMD
...
22126 0 0:00 slepp 1000
...
$ zap sleep
?22126
148/322 محیط برنامه سازی لینوکس
مسأله اين است که خروجي PSبه کلماتي بخش بخش شده که بوسیلة Pickبه عنوان آرگومانهای مجزا ديده ميشوند ،به جای اينکه
کل خط يك باره پردازش شود.
رفتار عادی پوسته ،شکستن رشتهها به آرگومانهايي است فاصله دار و بدون فاصله ،مانند:
For i in 1 2 3 4 5
در اين برنامه بايد تقسیمات پوسته را بر روی رشتهها ،به آرگومانها ،کنترل کنیم ،تا فقط خطوط جديد ،کلمات کنار هم را از هم جدا
کنند.
متغیر پوسته ( IFSجدا کنندة میدان داخلي) ،رشتهايست از کاراکترها که کلمات را در فهرست آرگومانها ،از هم جدا ميکند ،مانند ` و
جملت . forبه طور معمول ، IFS ،شامل يك جای خالي ،يك پرش و يك خط جديد مي باشد اما ميتوانیم آنرا به هر چیزمفیدی
تبديل کنیم ،مانند يك خط جديد:
$ echo ' echo $# ' >nargs
$ cx naegs
$ who
you tty0 0ct 1 05:59
pjw tty2 oct 1 11:26
`$ nargs `who
10 میدانهای مجزای ده خط و يك خط جديد
' = $ IFS
فقط يك خط جديد '
`$ nargs `who
2 دو خط جديد .دو میدان
$
:به خوبي کار ميکند ، zapتوسط خط جديد IFSبا مقدار دهي
$ cat zap
# zap pat: kill all procsses matching pat
# final version
22126
PATH= /bin :/usr/bin
'=IFS
' # just a newline
case $ 1 in
( '' '' ;; echo 'Usage: zap ]-2[ pattern' 1>&2; exit 1
(* – SIG= $1 ; shift
esac
' esac PID TTY 'TIME CMD
` ' {kill $SIG ` pick \` ps -ag | egrep '' $ * ''\` | awk '}print $1
$ ps – ag
PID TTY TIME CMD
...
22126 0 0:00 sleep 1000
149/322 محیط برنامه سازی لینوکس
...
$ zap sleep
PID TTY TIME CMD
22126 0 0:00 sleep 1000? y
23104 0 0:02 egrep sleep? n
$
ما دو چين خوردگي را وارد كرديم :يك آرگومان اختياري براي مشخص كردن سيگنال (توجه
كنيد كه SIGمعرفي نشده ميماند و از اين رو ،به عنوان يك رشتة بي تأثير تلقي خواهد
شد ،اگر آرگومان به كار گرفته نشود) و استفاده از egrepبه جاي ، grepبراي مجاز كردن
نمونههاي پيچيدهتر مانند .Sleep | date′ ′يك echoابتدايي ،سرصفحههاي ستوني را براي
خروجي Psبه چاپ مي رساند.
حتما ً تعجب خواهید کرد چرا اين فرمان به جای فقط zap ، killخوانده ميشود .دلیل اصلي اين است که برخلف مثال ما در مورد
، calدر حقیقت فرمان Killجديدی ايجاد نميکنیم ZAP :الزاما ً تبادلي است ،به يك دلیل -و ما ميخواهیم Killرا به همین دلیل
نگهداريم Zap .همچنین به طرز آزار دهندهای کند است -هزينه تمام برنامههای اضافي ،قابل قبول است ،با وجود آنکه ( Psکه بايد به
هر صورتي اجرا شود) گرانترين است.
در فصل بعد ،کارکردی مؤثر تر از ارائه خواهیم داد.
تمرين ZAP . ۵-۲۳را بگونهای تعريف کنید که سرصفحة PSرا از pipelineچاپ کند بطوريکه به تغییرات درساختار خروجي ، Ps
حساس نباشد .اين تغییر ،تا چه حد برنامه را پیچیده ميکند؟
ما تقريبا ً با هر آنچه برای نوشتن دستور pickدر پوسته نیاز داريم،بر خورد داشتهايم .تنها چیز جديدی که نیاز است ،مکانیزمي است
برای خواندن ورودی کاربر .دستور داخلي پوسته ، readيك خط از متن را از ورودی استاندارد خوانده و متن را به عنوان مقدار متغیر
نام برده مي خواند (بدون خط جديد).
$ read greeting
. hello , worldوارد کنید greetingمقداری جديد برای
$ echo $ greeting
hello , world
$
معمولترين استفاده readدر .profileاست جهت تنظیم محیط ،هنگام ورود به سیستم تا متغیرهای پوسته مقدار دهي اولیه شوند ،مانند
.TERM
Readفقط ميتواند از ورودی استاندارد بخواند؛ حتي قابل جهت دهي مجدد نیز نیست .هیچ يك از دستورات درون پوسته (برخلف
اصول اولیه کنترل جريان مانند ) forقابل جهت دهي مجدد با > يا < نیستند.
اين امر را ميتوان به عنوان نقصي در پوسته قلمداد کرد ،اما واقعیت دارد .خوشبختانه مي توان با دوباره جهت دادن حلقه محاط بر for
اين موضوع را نیز حل کرد .اين کلید مشکل ما در به کار بردن دستور pickاست:
# pick: select arguments
PATH= /bin:/usr/bin
for i # for each argument
do
echo -n ''$i? '' >/dev/tty
read response
case $response in
(*y ;; echo $i
(*q break
esac
done </dev/tty
echo-nآخرين خط جديد را متوقف ميکند ،تا پاسخ در آن ،به صورت يك پیغام فوری ،قابل تايپ شدن باشد .و البته پیغامهای فوری
در dev/tty/چاپ ميشوند ،چرا که خروجي استاندارد اغلب مطمئناً ترمینال نیست.
جملة breakاز C :قرض گرفته شده است :حلقة دروني احاطه شده را پايان ميدهد .در اين حالت ،حلقة Forرا هنگامي که qتايپ
شود ،قطع ميکند .اجازه ميدهیم qانتخاب را به پايان برساند چرا که انجام آن آسان است ،ذاتا ً بي زحمت و با ساير برنامهها نیز
سازگار است.
برای اجرای ، Pickاستفاده از جاهای خالي در آرگومانها ،جالب به نظر مي رسد:
$ pick ' 1 2 ' 3
?1 2
?3
اگر مايلید بدانید Pickچگونه آرگومانهای خود را انتخاب مي کند ،آنرا اجرا کرده و فقط پس از هر پیغام فوری Return ،را فشار
دهید .همانگونه که انتظار ميرود ،درست عمل ميکند For i :آرگومانها را درست جابجا ميکند .ميتوانستیم حلقه را به روشهای
ديگری بنويسیم:
$ grep for pick see what this version does
* for i in $
$ pick '1 2' 3
?1
?2
?3
151/322 محیط برنامه سازی لینوکس
$
اين فرم جواب نميدهد ،زيرا عملگرهای حلقه دوباره جاروب ميشوندو جاهای خالي در اولین آرگومان ،باعث ميشود به دو آرگومان
تبديل شوند .اين بار باگذاشتن " برای* $امتحان کنید.
$ grep for pick نسخه ای ديگر را امتحان کنید
''*for i in ''$
$ pick ' 1 2 ' 3
?1 2 3
$
اين يکي نیز کار نميکند ،چرا که ˝ * ˝ $کلمهايست مفرد و متشکل از تمامي آرگومانهايي که به يکديگر پیوسته اند و با جای خالي از
هم جدا شدهاند.
البته راه حلي وجود دارد ،اما تقريباً شعبده بازی است :رشتة ˝ @ ، ˝ $توسط پوسته ،به طور ويژهای مورد توجه قرار ميگیرد و دقیقاً
به آرگومانهای فايل پوسته تبديل ميشود:
$ grep for pick نسخه سوم را امتحان کنید
''@for i in ''$
$ pick ' 1 2 ' 3
?1 2
?3
$
اگر @ $داخل کوتیشن قرار نگرفته باشد ،همانند * $تلقي ميگردد؛ رفتار فقط هنگامي مخصوص خواهد بود که داخل ˝ قرار گیرد،
از آن در Overwriteبرای نگهداشتن آرگومانها برای دستور کاربر استفاده کرديم.
به طور خلصه ،قوانیني در اينجا ذکر ميگردند:
•* $و @ ، $به آرگومانها توسعه داده و دوباره جاروب مي شوند؛ جاهای خالي در آرگومانها ،آرگومانهای متعددی را نتیجه خواهد
داد.
• ''* ''$کلمه ايست منفرد ،مرکب از تمامي آرگومانهای موجود در پوسته که با فاصله هايي به يکديگر متصل شده اند.
•* ''@ ''$مشابه آرگومانهايي است که بوسیله فايل پوسته دريافت مي گردند :جای خالي در آرگومانها ناديده گرفته ميشوند و
نتیجه ،فهرستي است از کلماتي که يکسان با آرگومانهای اصلي هستند.
اگر Pickآرگوماني نداشته باشد ،بايد ورودی استاندارد خود را بخواند ،از اين رو ميتوان از:
$ Pick > < mailing list
به جای
` $ Pick ̀Cat mailing list
استفاده کرد .اما ما اين نسخه از Pickرا مورد بررسي قرار نميدهیم :با پیچیدگيهای ناهنجاری همراه است و بسیار مشکلتر از برنامة
مشابهي است که با Cنوشته ميشود ،که در فصل بعد آنرا بحث خواهیم کرد.
دو تمرين اول پیش رو مشکل ميباشند ،اما برای برنامهنويسان پیشرفته پوسته ،آموزندهاند.
152/322 محیط برنامه سازی لینوکس
ما دو چین خوردگي را وارد کرديم :يك آرگومان اختیاری برای مشخص کردن سیگنال (توجه کنید که SIGمعرفي نشده ميماند و از
اين رو ،به عنوان يك رشتة بيتأثیر تلقي خواهد شد ،اگر آرگومان به کار گرفته نشود) و استفاه ازـ egrepبه جایـ ، grepبرای
مجازکردن نمونههای پیچیدهتر مانند ' . 'sleep | dateيك echoابتدايي ،سرصفحههای ستوني را برای خروجي psبه چاپ ميرساند.
تمرين . ۵-۲۴سعي کنید با pickبرنامهای بنويسید که آرگومانهايش را از ورودی استاندارد بخواند ،اگر هیچ کدام در خط فرمان عرضه
نشده باشند .بايد جاهای خالي را به خوبي کنترل کند .آيا qکار مي کند؟ اگرنه ،تمرين بعدی را امتحان کنید.
تمرين . ۵ -۲۵با وجود اينکه دستورات دروني پوسته مانند readو setقابل جهت دهي مجدد نیستند ،خود پوسته ،موقتا ً قابل جهت
دهي است .بخش مربوط به ( sh)1را که enecرا توصیف کرده و چگونگي خواندن از ، dev/ttyرا بدون فراخواني يك زير پوسته،
کامل تشريح ميکند ( .ممکن است خواندن فصل ۷بتواند کمك کند) .
تمرين (. ۵ -۲۶بسیار سادهتر) readرا در . protileخود بخوانید و TERMو هرآنچه به آن بستگي دارد را بنويسید.
در فصل اول ،اشاره کرديم که سیستم شما ممکن است دارای يك فرمان newsجهت گزارش پیغامهای عمومي جامعة کاربر باشد.
باوجود اينکه نام و جزيیات دستور تفاوت دارند ،اکثر سیستمها ،دارای يك سرويس خبری است .دلیل ما برای ارائة فرما ن news
جايگزين کردن دستور محلي شما نیست بلکه برای اينست که نشان دهیم به چه سادگي چنین برنامهای را در پوسته ،ميتوان نوشت.
مقايسة دستور newsما با ويرايش محلي شما ،ميتواند جالب باشد.
ايدة ابتدايي چنین برنامهای ،اين است که مقالت خبری ،هرکدام در يك فايل ،در يك دايرکتوری ويژه مانندـ usr/news/ذخیره
ميشوند(news .برنامة )،newsازمقايسة زمانهای تعريف فالها در usr/news/با همان نمونهها در دايرکتوری شما (). news-time
عمل ميکند.
ميتوانیم از « » .به عنوان دايرکتوری برای هم فايلهای خبری و هم . news-timeاستفاده کنیم; که هنگام آماده بودن برای اشکال
زدايي،برنامه جهت استفاده عمومي ،قابل تغییر به usr/news/ميباشد.
$ cat news
# news: print news files, vrsion 1
HOME=. # debugging only
cd . # place holder for /usr/news
` for i in `1s -t * $ HOME/ . news – time
do
case $i in
(• / .news – time ;; break
( • echo news: $i
• 22126
esac
done
touch $HOME/ . news – time
$ touch x
$ touch y
153/322 محیط برنامه سازی لینوکس
$ news
news : y
news : x
$
touchزمان آخرين تغییر فايل آرگومان خود را به زمان حال تغییر ميدهد ،بدون تغییری در فايل ،برای عیب يابي ،فقط اسامي فايلهای
خبری را بازگشت ميدهیم ،به جای اينکه آنها را چاپ کنیم.
حلقه وقتي پايان مييابد که . news-timeرا بیابد ،از آن به بعد ،تنها آنهايي را فهرست ميکند که جديدتر باشند .دقت کنید که * در
جملت ،caseميتواند با يك /مطابقت داشته باشد.
چه اتفاقي ميافتد اگر . newd-timeوجود نداشته باشد؟
$ rm .news – time
4 news
$
اين سکوت ،غیر منتظره است و اشتباه ،اما رخ ميدهد چرا که اگر LSنتواند فايلي را بیابد ،در خروجي استاندارد خود ،پیش از چاپ
هر اطلعاتي دربارة فايلهای موجود ،وجود مشکلي را گزارش ميدهد .اين يك عیب بوده اما ما ميتوانیم آنرا با تشخیص مشکل در
حلقه ،حل کنیم و خطای استاندارد را به خروجي استاندارد دوباره جهت دهیم( .اين شکل درنسخههای جديدتر سیستم حل شده بود) .
$ cat news
# news: print news files, version 2
HOME= . # debugging only
cd . # place holder for / usr/news
' = IFS
' # just a newline
`for i in ` 1s – t * $ HOME/ .news – time 2>&1
do
case $i in
( ' • ' not found ;;
( • / .news – time ;; break
( • ;; echo news : $i
esac
done
touch $ HOME/ .news – time
$ rm .news – time
$ news
news : news
news: y
news: x
$
در قدم بعدی news ،بايد فايلهای خبری را چاپ کند ،به جای آنکه نام آنها را برگرداند .اين کار از اين بابت مفید است که ميتوان
فهمید چه کسي و چه زماني را ارسال نموده ،و از اين رو از دستور setو LS-1برای چاپ يك سرصفحه قبل از خود پیغام ،استفاده
ميکنیم:
$ 1s -1 news
– r wxrwxrwx 1 you 208 o ct 1 12:05 news
اين يك غالب قابل قبول است و نويسنده و تاريخ پیغام را همراه با نام فايل نشان ميدهد.
در اينجا آخرين ويرايش دستور newsآمده است:
# news: print news files , final version
PATH= /bin:/usr/bin
' =IFS
' # just a newline
cd/ usr/news
`for i in `1s - t * $ HOME/ .news – time 2>&1
do
' ' =IFS
case $i in
;; ( ' • ' not found
;; • /.news – time( break
( • `set X` 1s -1 $i
'' echo
$i : )$3( $5 $6 $7
cat $i
esac
done
touch $HOME/ . news - time
155/322 محیط برنامه سازی لینوکس
خطوط جديد اضافي در سرصفحه ،مقالت خبری را در حین چاپ از هم جدا ميکنند .اولین مقدار ، IFSفقط يك خط جديد است،
از اين رو پیغام ( not faundاگر باشد) از اولین ، LSبه عنوان يك آرگومان منفرد تلقي ميگردد .دومین وظیفة ،IFSآنرا دوباره جای
خالي مقدار دهي ميکند ،از اين رو خروجي دومین ،LSبه آرگومان هايي تجزيه ميکند.
تمرين . ۵-۲۷يك گزينه -nرا به newsاضافه کنید تا مقالت خبری را گزارش دهد اما چاپ نکند و به . news – timeدست نیابد.
ممکن است در . profileشما جای گیرد.
. ۵-۲۸طرح ،و کارکرد newsدر دستورات مشابه روی سیستم خود را با يکديگر مقايسه کنید.
در اين بخش ،تا آخرين بخش يك فصل طولني ،يك مثال بزرگتر و پیچیدهتر را به بحث ميگذاريم که همکاری پوسته را با sed ,
، awkتشريح ميکند.
يك برنامه ،با درست کردن معايب و اضافه کردن ويژگیها ،تکامل مييابد .گاهي رديابي اين ويرايشها ،به ويژه هنگامي که افراد برنامه را
برای ساير ماشینها به کار ميبرند ،ساده مينمايد ـ برميگردند سئوال ميکنند « از وقتي که ويرايش ما نصب شده ،چه تغییری حاصل
شده؟ » يا « اين عیب يا آن مشکل را چگونه برطرف کرديد؟ » همچنین ،همواره نگهداشتن نسخههای پشتیبان ،تجربه کردن ايدهها را
بيآسیب تر ميکند :اگر چیزی کار نميکند ،بازگشتن به برنامه اصلي ،بدون دردسر خواهد بود .يك راه حل ،نگه داشتن کپيهای تمام
ويرايشهاست ،اما اين کار با زحمت و هزينة زيادی همراه است .درعوض ،بر روی نسخههايي متمرکز ميشويم که دارای بسیاری
قسمتهای مشترك بوده و يکبار نیاز به ذخیره شدن دارند.
$ diff - e old new دستور
فهرستي از دستورات edرا که oldرا به newتبديل ميکنند ،ايجاد ميکند ،از اين رو نگهداشتن تمامي نسخههای يك فايل در يك
فايل جداگانه (متفاوت) با نگهداری يك نسخة کامل و مجموعهای از دستورات ويرايشي برای تبديل آن به هر نسخه ،میسر ميشود.
دو نوع سازماندهي وجود دارد :جديدترين ويرايش را در دسترس نگه داشته و دستورات ويرايشي را عقب برد و يا قديميترين
ويرايش ها را نگه داشت و دستورات ويرايشي را جلو برد .باوجود اينکه دومي برای برنامه نويسي سادهتر است ،اولي سريعتر است اگر
ويرايشهای زيادی در دسترس باشد .ما سازماندهي اول را انتخاب ميکنیم .در يك فايل منفرد که آنرا فايل تاريخچه نام گذاری ميکنیم،
ويرايش جاری و در پي آن مجموعهای از دستورات ويرايشي که هر ويرايشي را به ويرايش قبلي برميگرداند ،موجود مي باشند.
هرمجموعه از دستورات ويرايشي ،با خطي شروع ميشوند مشابه
@@@ شخص تاريخ خلصه
خلصه ،خطي است منفرد ،که بوسیله شخص تأمین شده و تغییر را توصیف مينمايد .برای نگهداری از نسخهها ،دو دستور وجود
دارد get :ويرايشي را از فايل تاريخچه گرفته و putنسخهای جديد را به آن وارد مينمايد ،پس از اينکه يك خط خلصة تغییرات
درخواست شود.
پیش از نشان دادن کاربرد ،مثالي در اينجا برای بیان چگونگي عمل getو putو فايل تاريخچه چگونه نگهداری ميشود ،آورده شده:
156/322 محیط برنامه سازی لینوکس
. ويرايش جديد را به نسخة اصلي برميگرداند، که خط دوم فايل را از بین ميبرند2d « دستورات ويرايشي » شامل خط منفرد
$ rm junk
$ get junk جديدترين ويرايش
$ cat junk
a line of text
another line
$ get -1 junk
$ cat junk ويرايش يکي مانده به آخر
a link of text
$ get junk جديدترين ويرايش دوباره
$ reolace antother 'a different ' junk
$ put junk
summary: second line changed
$ cat junk . H
a line of text
a different line
@@@ you sat oct 1 13:34:07 EDT 1983 second line changed
2c
another line
.
@@@ you sat oct 1 13:32:28 EDT 1983 one line added
2d
@@@ you sat oct 1 13:31:03 EDT 1983 make a new file
$
157/322 محیط برنامه سازی لینوکس
دستورات ويرايشي ،از بال تا پايین سراسر فايل تاريخچه ،اجرا شده تا ويرايش دلخواه را استخراج کنند :سری اول ،جديدترين را به
دومین نسخة جديد تبديل ميکند ،بعدی آن را به سومین نسخة جديد برميگرداند و … از اين رو ،درواقع فايل جديد را هر بار با
اجرای edيکي ،به نسخة قديمي برميگردانیم.
اگر فايلي را که با @@@ آغاز شده باشد را مورد اصلح قرار دهیم ،قطعا ً به مشکل برخواهیم خورد و بخش عیبها از (،diff)1
درباره خطوطي که شامل فقط يك دوره ميشوند ،اخطار خواهد داد .ازـ @@@ برای علمت گذاری دستورات ويرايشي استفاده
ميکنیم ،چرا که رشتهايست ناخواسته برای متني معمولي.
باوجود آنکه نشان دادن چگونگي تکامل دستورات getو ، putميتواند مفید واقع شود ،اما طولني بوده و نشان دادن فرمهای گوناگون
آنها ،مستلزم بحث زيادی است .از اين جهت تنها فرمهای نهايي آنها را به شما نشان ميدهیم Put .سادهتر است:
# put: install file in to history
PATH=/bin: / usr / bin
case $# in
(1 ;; HIST=$1 . H
(2 ;; echo ' Usage: put fill ' 1>&2; exit 1
esac
if test ! -r $1
then
echo ''put: can ' t open $1'' 1>&2
exit 1
fi
trap 'rm -f /tmp/put . ]ab[$$; exit 1' 1 2 15
' echo -n ' Summary:
read Summary
if get -o /tmp/put.a$$ $1 # previous versoin
then # merge pieces
cp $ 1 /tmp/put.b$$ # current versin
echo ''@@@ ` getname ` `date` $Summary '' >>/tmp/put.b$$
diff -e $1 /tmp/put.a$$ >>/tmp/put.b$$ # Latest diffs
sed -n '/^@@@/, $p' <$HIST >>/tmp/put.b$$ # old diffs
overwrite $HIST cat /tmp/put.b$$ # put it back
else # mske a new one
''echo ''put: creating $HIST
cp $1 $HIST
echo ''@@@ `getname ` ` date` $Summary'' >> $HIST
fi
rm -f /tmp/put.]ab[$$
بعد از خواندن خلصة يك خطي put ger ،را جهت استخراج ويرايش قبلي فايل از فايل تاريخچه ،فراخواني ميکند .گزينة ، -oيك
فايل خروجي متبادل را به getاختصاص ميدهد .اگر getنتوانست فايل تاريخچه را بیابد ،يك پیغام خطا برگردانده و putيك فايل
تاريخچه جديد ايجاد ميکند .اگر فايل تاريخچه وجود داشته باشد ،عبارت ، thenتاريخچه جديد را در يك فايل موقت ،به ترتیب از
آخرين ويرايش ،خط @@@ دستورات ويرايشگر ،برای تبديل از جديدترين ويرايش قبلي ،ايجاد ميکند .سرانجام ،فايل موقت روی
158/322 محیط برنامه سازی لینوکس
خط
test -r $INPUT | | } echo '' get: no file $INPUT'' 1>&2; exit 1; {
مورد استفاده قرارميگیرد version( .ميتواند نام فايل تاريخچه را برای سادگي کار برگرداند).
تمرين get . ۵-۳۰و putرا طوری تعريف کنید که فايل تاريخچه را دريك دايرکتوری جداگانه ،به خوبي به کار بندد .به جای اينکه
دايرکتوری در حال کار را با فايلهای .Hشلوغ کند.
. ۵-۳۱تمامي ويرايشهای يك فايل ،پس از سامان گرفتن همه چیز ،ارزش حفظ کردن ندارند .چگونه ميتوانید ترتیبي اتخاذ کنید که
ويرايشهايي را از میان فايل تاريخچه حذف کنید.
هنگامي که بانوشن يك برنامه مواجه ميشويد ،تمايلي طبیعي به شروع به فکر کردن به اين موضوع وجود دارد که آنرا به زبان مورد
علقه خودتان بنويسید .در اين مورد ،آن زبان ،پوسته است.
باوجود آنکه گاهي رسم الخطي نامأنوس دارد ،پوسته زبان برنامهنويسي مناسبي ميباشد .مطمئناًـ سطح آن بالست؛ عملگرهای آن
برنامههايي هستند کامل .از آنجايیکه تبادلي ميباشد ،برنامهها ميتوانند بصورت تبادلي توسعه پیدا کنند و در چند قدم و در حین کار
160/322 محیط برنامه سازی لینوکس
قابل پاليش شدن هستند .بعد از آن ،اگر جهت کارهايي غیرشخصي نیز نیاز باشند ،با پرداخته و محکم کاری شدن ،ميتوانند جهت
استفادههای متنوعتر آماده شوند .در آن حالت غیرمعمولي که پوسته بايد بسیار کارآمد باشد ،برخي ،يا تمام برنامههای آن ميتوانند با
Cنوشتهشوند ،اما باز هم با طرح دستنويس( .اين روش را در فصل بعد به بحث خواهیم گذاشت).
در اين فصل بسیاری مثالها را که با برنامهها و پوستههای موجود راحت قابل انجام هستند ،آورده شدهاند .گاهي دوباره مرتب کردن
آرگومانها ،کافي ميباشد؛ در حالتي که با calکار ميکنیم .گاهي پوسته حلقهای بر يك مجموعه از نام فايلها يا يك توالي از اجرای
دستورات ،ايجاد ميکند ،مانند . checlcmail , watchforمثالهای پیچیدهتر ،نسبت به ،Cکمتر کار ميبرند ؛ برای مثال ويرايش ۲۰
خطي ما از ،newsجايگزين ويرايش ۳۵۰خطي Cشده است.
اما اينها برای داشتن يك زبان دستورات قابل برنامهريزی ،کافي نیست .آنچه اهمیت دارد ،اين است که تمامي اجزاء با هم کار کنند .
هرکدام برای تمرکز بر روی يك کار و انجام بهینه آن طراحي شدهاند ،سپس پوسته آنها را هرگاه که ايدهای جديد داريد ،با هم پیوند
ميدهد ،به راحتي و با کارايي بال ،همین همکاری باعث ميشود که محیط برنامهنويسي UNIXبسیار کارآمد باشد.
ايدة ، put , getاز سیسم کنترل که مرجع ( )sccsکه بوسیلة Marc Rochkindايجاد شده ،ميآيد sccs ، IEEE "( .ترجمهای بر
مهندسي نرمافزار sccs . )1975 ،بسیار توانمند و انعطاف پذيرتر از برنامههای سادة ماست؛ جهت نگهداری برنامههای عظیم در يك
محیط تولیدی کاربرد دارد .مبنای sccsمشابه برنامه diffاست.
161/322 محیط برنامه سازی لینوکس
يك کتاب درسي عالي cنوشته شده توسط دو نويسنده شناخته شده و بسیار بزرگ:
زبان برنامه نويسي ANSI C-C
بريان W.Cکرينان و دنیس .Mريتچي
فرنتیس هال ۱۹۸۸
دنیس ريتچي اولین مترجم Cرابر روی PDP-11طراحي و پیاده سازی کرد(ماشین ماقبل تاريخ با استانداردهای امروزی ،که تاکنون
تاثیر زيادی بر محاسبات علمي مدرن داشته است ).زبان cبر مبنای دو زبان ( اکنون از بین رفته ) بوده( BCPL :بي سي پي ال) ؛
مارتین ريجاردز ،و ( Bبي) نوشته کن تامپسون در سال ۱۹۷۰برای اولین سیستم يونیکس بر روی . PDP_7زبان اصلي و رسمي R:C
و Kبود .که برگرفته از نام دو نويسنده زبان برنامه نويسي cاصلي بوده است .در سال ۱۹۸۸موسسه استانداردهای ملي آمريکا (
)ANSIنسخه جديدو اصلح شده cرا که امروزه با عنوان ( ) ANSI Cشناخته شده را پذيرفت.
اين نسخه در ويرايش جاری زبان برنامه نويسي ANSI C-Cتوصیف شده .نسخه ANSIشامل اصلحیه های زياد نحوی و کارهای
دروني زبان مي باشد .موارد مهم اصلح شده نحو فراخواني برای روالها و استاندارد سازی بیشتر کتابخانه های سیستم است ( ولي،
متاسفانه نه تمام آنها)
تابع «( »mainاصلي) در بالی برنامه قرار مي گیرد .بطورمعمول کوتاه بوده و توابع مختلف را برای اجرای زير – وظايف فراخوني مي
کند .همه کدهای cبايد دارای تابع mainباشند.
کد printf ,hello.cرا که يك تابع خروجي از کتابخانه ( I/Oورودی /خروجي) که در فايل stdio.hتعريف شده) را فراخواني مي
کند .زبان اصلي cبه هیچوجه دارای حکم های I/Oتوکار (دروني ) نمي باشد .توابع رياضي زيادی نیز ندارد .زبان اصلي واقعا به
منظور محاسبات علمي يا تکنیکي نبوده ...اين توابع اکنون توسط کتابخانه استاندارد اجرا مي شوند ،که اکنون بخشي از ANSI C
هستند .کتاب K & Rمحتوای اينها و کتابخانه های استاندارد ديگر در ضمیمه ( پیوست ) را فهرست مي کند.
خط printfپیام hello wordرا بر ( stdoutمسیر خروجي متناظر با پنجره ترمینال يا پايانه xدر آنچه شما کد را اجرا مي کنید )
چاپ مي کند.
“ ”/nيك خط جديد چاپ نموده ،که کرسور را به خط بعدی مي آورد .توسط ، printfاين خط هرگز ايجاد نمي شود .برنامه زير
همین نسخه را تولید مي کند:
<include < stdio.h#
()void main
}
;("printf)"\n
;("printf)"Hello World
;("printf)"\n
{
محاسبه
. درجه محاسبه مي کند۳۶۰ تا۰ را برای زاويه های بینsine جدولي از توابعsine.c ،برنامه زير
/************************/
/* Table of */
/* Sine Function */
/************************/
/* Michel Vallieres */
/* Written: Winter 1995 */
void main)(
}
int angle_degree;
double angle_radian, pi, value;
/* Print a header */
printf )"\nCompute a table of the sine function\n\n"(;
۳حلقه ها:
اکثر برنامه های واقعي شامل ساختاری است که در برنامه حلقه مي زند .اجرای عملهای مکرر در يك جريان داده يا ناحیه ای از حافظه.
چندين روش برای حلقه در cوجود دارد .دو حلقه بسیار رايج يکي whileاست.
( whileعبارت )
{ ...............بلوك دستورات برای اجرا ......
}
؛ عبارت ۱
( whileعبارت )۲
{
.......بلوك دستورات ........
؛ عبارت ۳
}
برای نمونه ،ساختار زير اغلب مشاهده مي شود:
i = iمقدار اولیه ;
while ) i < = iماکزيمم )
{
...بلوك دستورات ...
i = i + iنمو ;
}
اين ساختار با نحو آسانتر حلقه forبازنويسي مي شود:
= for )iمقدار اولیه ; = >iحداکثر ; = i + iنمو
{
........بلوك دستورات ............
}
حلقه بي نهايت نیز ممکن است ( برای مثال ( ; ; ) . ) forولي برای هزينه کامپیوتر خیلي خوب نیست!
166/322 محیط برنامه سازی لینوکس
cبه شما اجازه نوشتن حلقه بي نهايت را مي دهد و دستور breakرا برای شکستن و خروج از حلقه فراهم کرده است.
برای مثال ،به مثال زير که بازنويسي شده حلقه قبلي است توجه کنید:
;angle_degree = 0
( ; ; ) for
}
.........بلوك دستورات ...........
;angle_degree = angle_degree + 10
;if )angle_degree == 360( break
{
شرط ifبه طور ساده مي پرسد آيا angleـ ( degreeدرجه زاويه ) مساوی ۳۶۰هست يا نه؛
اگر هست ،حلقه تمام شود ( بايستد)
ثوابت نهادی
شما مي توانید ثابت های هر نوع را با استفاده از راهنمای مترجم # defineتعريف کنید ،نحو آن ساده است .
برای نمونه
٫#define ANGLE_MIN 0
#define ANGLE_MAX 360
ANGLE_MAx,ANGLE_MINرا به ترتیب مقادير ۰و ۳۶۰درجه تعريف مي کند C .بین حروف کوچك و بزرگ در نام متغیرها
تفاوت قائل مي شود .معمول است که از حروف بزرگ در تعريف ثابتهای سراسری استفاده شود.
شرطها
شرط ها با ساختارهای ifو whileاستفاده مي شوند.
if ) iشرط )
{
.............بلوك دستورات اجرايي اگر شرط ۱درست باشد .........
}
( eles ifشرط ) ۲
{
......بلوك دستورات اجرايي اگر شرط ۲درست باشد ......
}
else
{
.........بلوك دستورات اجرايي در غیر اينصورت ...........
}
167/322 محیط برنامه سازی لینوکس
اشاره گرها
زبان cبه برنامه نويس اجازه خواندن و نوشتن در محلهای حافظه را بطور مستقیم مي دهد .اين قابلیت انعطاف بال وقدرت زبان رانشان
مي دهد .البته يکي از موانع بزرگي است که برنامه نويس مبتدی بايد دراستفاده از زبان چیره شود.
همه متغیر های يك برنامه در حافظه مقیم هستند .دستورات
; float X
x = 6.5
نیاز دارد که مترجم ۴بايت از حافظه را در يك کامپیوتر ۳۲بیتي برای متغیرهای ممیز شناور xذخیره کند و سپس مقدار 6.5را درآن
قرار دهد.
گاهي اوقات ما مي خواهیم بدانیم يك متغیر در کجاهای حافظه مقیم است .آدرس ( مکان در حافظه ) هر متغیر با قرار دادن عملوند
"&” قبل از نام آن بدست مي آيد .بنابراين & ampxآدرس xاست.
cبه ما امکان رفتن به مرحله بالتر و تعريف متغیر را مي دهد ،که اشاره گر نامیده مي شود .شامل آدرس ( يعني "( ) “ points to
اشاره به ) متغیر های ديگراست .برای مثال
;float x
;float* px
;x = 6.5
;px = &x
pxرا به عنوان اشاره گر به اشیاء نوع شناور تعريف مي کند ،و آن را برابر با آدرس xقرار مي دهد
محتوای مکان حافظه رجوع شده توسط اشاره گر با استفاده از عملوند "*” بدست مي آيد ( .اين اشاره گر ،اشاره گر مرجع نامیده مي
شود )
بنابراين *px ،به مقدار xمراجعه مي کند.
cبه ما اجازه اجرای عملگرهای حسابي را با استفاده از اشاره گرها مي دهد .البته آگاه باشید که واحد( )UNITدر اشاره گر حسابي
اندازه ( بر حسب بايت ) شي که اشاره گر ،به آن اشاره مي کند است .برای مثال ،اگر pxيك اشاره گر به متغیر xاز نوع حقیقي باشد،
عبارت px + 1به بیت يا بايت بعدی حافظه مراجعه نمي کند بلکه به مکان نوع حقیقي بعد از ( xچهار بايت بعد در بیشترايستگاههای
کاری) مراجعه مي کند.
اگر xاز نوع مضاعف باشد px +1به مکان ۸بايت ( اندازه مضاعف ) بعد مراجعه مي کند .و مانند آن .فقط اگر xاز نوع کاراکتر باشد
px +1واقعا به بايت بعدی در حافظه مراجعه مي کند.
بنابراين ،در
;char* pc
;float* px
;float x
;x = 6.5
;px = &x
169/322 محیط برنامه سازی لینوکس
اين کد را اجرا کنید و نتايج اين عملوند های مختلف را ببینید .دقت کنیدکه ،زمانیکه مقدار اشاره گر ( اگر شما آن را با printfچاپ
کنید ) نوعا يك متغیر بزرگ است؛ مکان خاصي از حافظه در کامپیوتر ،را مشخص مي کند .اشاره گرها مقادير صحیح نیستند – آنها
يك نوع داده کامل متفاوت هستند.
۷آرايه ها:
در ،cآرايه ها از 0شروع مي شوند .عناصر آرايه مکانهای مجاور در حافظه را اشغال مي کنند.
cبا نام آرايه مانند اينکه آنها يك اشاره گر به اولین عنصر باشد رفتار مي کنند .اين در فهمیدن اينکه چگونه محاسبات توسط آرايه ها
انجام گیرد مهم است .بنابراين ،اگر vيك آرايه باشد *Vيك چیزی است نظیر [ *)v+1( , v]0چیزی نظیر [ v]1و به همین
ترتیب.
به کد زير توجه کنید ،که کاربرد اشاره گرها را با مثال توضیح مي دهد .
#define SIZE 3
()void main
}
;[float x]SIZE
;float *fp
;int i
/* initialize the array x */
/* use a "cast" to force i */
/* into the equivalent float */
(for )i = 0; i < SIZE; i++
;x]i[ = 0.5*)float(i
/* print x */
(for )i = 0; i < SIZE; i++
;([printf)" %d %f \n", i, x]i
/* make fp point to array x */
;fp = x
/* print via pointer arithmetic */
/* members of x are adjacent to */
/* each other in memory */
/* *)fp+i( refers to content of */
/* memory location )fp+i( or x]i[ */
(for )i = 0; i < SIZE; i++
;((printf)" %d %f \n", i, *)fp+i
{
( عبارت " ”i++مختصر نويسي cبرای " ”i= i+1است ) x]i [ .يعني iاولین عنصر آرايه fp=x, xبه شروع xاشاره مي کند ،سپس
( *)fp+iمحتوای آدرس iمکانهای بعد از fpاست .که [ x]iمي باشد.
171/322 محیط برنامه سازی لینوکس
کدهای cهیچ عملوندی را برای دستکاری يکباره رشته های درست فراهم نکرده .رشته ها يا توسط اشاره گرها يا از طريق روال های
خاص قابل دسترسي از کتابخانه استاندارد رشته stringدستکاری مي شوند .استفاده از اشاره گر کاراکتری نسبتا ساده است چون نام
آرايه فقط اشاره گر به اولین عنصر آن مي باشد.
به کد زير توجه کنید:
()void main
}
;[char text_1]100[, text_2]100[, text_3]100
;char *ta, *tb
;int i
/* set message to be an arrray */
/* of characters; initialize it */
/* to the constant string "..." */
/* let the compiler decide on */
[] /* its size by using */
;"?char message][ = "Hello, I am a string; what are you
}
k & توصیف اين کتابخانه در پیوست کتاب.کتابخانه استاندارد رشته شامل توابع مفید زيادی است ك رشته ها را دستکاری مي کنند
: بعضي از توابع مفیدتر عبارتند از. يافت مي شودR
. را برمي گرداندs. \” ؛0" شامل. کپي مي کندs را به داخلct : char* strcpy )c,cf(
. را بر مي گرداندs ، کپي مي کندs را به داخلct کاراکترn : char * strncpy)c, cf, n(
. را بر مي گرداندs الحاق مي کند؛s را به انتهایct : char * strncat )c, ct(
. را بر مي گرداندs; \” خاتمه يافتهn" با، االحاق مي کندs را به انتهایct کاراکترn :char* strncat )c, ct, n(
مقدار مثبت را برميcs>ct مقدار منفي و اگرcs<ct اگر، 0 باشدcs=ct را مقايسه مي کند؛ اگرct وcs : int strcmp )cs,ct(
گرداند
. را بر مي گرداندNULL را بر مي گرداند يا مقدارcs درc اشاره گر به اولین رخداد:char* strchr )cs, c(
. را بر مي گرداندcs طول:size – t strlen )cs(
). يك نوع صحیح استn تبديل شده به صحیح وchar يك کاراکتر از نوعc ، char* ثابتct وcs . هستندchar * از نوعt وs (
. توجه کنید.به کد زير که از بعضي از اين توابع استفاده مي کند
#include < string.h>
void main)(
}
char line]100[, *sub_text;
/* initialize string */
strcpy)line,"hello, I am a string;"(;
printf)"Line: %s\n", line(;
/* add to end of string */
strcat)line," what are you?"(;
printf)"Line: %s\n", line(;
/* find length of string */
/* strlen brings back */
/* length as type size_t */
}
( cاز طريق کتابخانه هايش ) روتین های گوناگون 1/0را فراهم کرده است .در سطح کاراکتر ( ) getcharکاراکتر را در يك زمان
از stdinمي خواند .هنگامیکه ( ) putcharيك کاراکتر را در يك زمان روی stdoutمي نويسد .برای مثال ،توجه کنید:
()void main
}
;int i, nc
;nc = 0
;()i = getchar
} (while )i != EOF
;nc = nc + 1
;()i = getchar
{
;(printf)"Number of characters in file = %d\n", nc
{
اين برنامه تعداد کاراکترها را در جريان ورودی مي شمارد ( .مثل در يك فايل لوله شده در زمان اجرا)
کد کاراکترها را (هر چقدرممکن است باشند) از ( stdinصفحه کلید) خوانده stdout ،را (پايانه xکه شما از آن اجرا مي کنید) برای
خروجي استفاده نموده و پیام خطايي برای ( stderrمعمول پايانه xشما) مي نويسد .اين جريانات همیشه در زمان اجرا تعريف مي
) getcharهنگامیکه در زمان شوند( EOF .پايان فايل) مقدار مشخصي را بر مي گرداند .که درـ stdiohتعريف شده وتوسطـ (
خواندن با نشانه end- of-fileمواجه شد ،بر گردانده مي شود .مقدار آن به کامپیوتر بستگي دارد .البته کامپايلر cاين واقعیت را از کاربر
با تعريف متغیر EOFپنهان مي کند .بنابراين برنامه کاراکتر ها را از stdinخوانده و مجموع آن را در شمارنده ncنگه مي دارد .تا
زمانیکه با "( ”end of fileانتهای فايل) روبرو شود.
يك برنامه نويس با تجربه cاحتمال اين برنامه را به صورت زير کد مي کند :
<include < stdio.h#
()void main
}
;int c, nc = 0
174/322 محیط برنامه سازی لینوکس
()void main
}
;int c, nc = 0, nl = 0
اين کد را ترجمه و اجرا کنید؛ سپس ويرايشگری را برای خواندن فايل foo.datبکار ببريد.
توابع
توابع برای استفاده آسانند؛ آنها اجازه می دهند كه برنامه های پيچيده به بلوک های كوچک تری تجزیه شوند ،هر كدام از آنها
برای نوشتن ،خواندن و نگهداری آسانترند .ما تا كنون با تابع mainبر خورد داشته و روال های ریاضی از كتابخانه های استاندارد
استفاده كرده ایم .اكنون اجازه دهيد به برخی دیگر از توابع كتابخانه ای و چگونگی نوشتن و استفاده از آنها نگاهی بيندازیم .
فراخواني يك تابع
فراخواني يك تابع در Cبسادگي شامل مراجعه به نام آن توسط نشانوندهای مناسب مي باشد .مترجم مطابقت بین آرگومانها در دنباله
فراخواني و تعريف تابع را بررسي مي کند.
توابع کتابخانه ای عموما در فرم منبع در دسترس ما نیستند .بررسي نوع نشانوند از طريق استفاده از فايلهای سرآيند ( مانند ) stdion.h
انجام مي شود که شامل همه اطلعات لزم مي باشد .برای مثال ،همانطور که بزودی خواهیم ديد ،بمنظور استفاده از کتابخانه رياضي
استاندارد شما بايد math.hرا از طريق دستور
> # include <math.h
در بالی فايل محتوی کدتان اضافه کنید .فايلهای سرآيند رايجتر عبارتند از:
> : <stdio.hتعريف روالهای I/O
> : <ctype.hبعريف روالهای دستکاری کارکترها
> : <string.hتعريف روالهای دستکاری رشته
> : <math.hتعريف روالهای رياضي
> : <stdlib.hتعريف تبديل عدد تخصیص حافظه و وظايف ( کارهای ) مشابه
> :<time.hتعريف روالهای زمان دستکاری
به علوه ،فايلهای سرآيند زير هم موجود است:
> :<assert.hتعريف روالهای تشخیص
> :<setjmp.hتعری فرآخواني های تابع غیر محلي
> : <signal.hبعريف گرداننده های سیگنال
> :<limits.hتعريف ثابت هايي از نوع صحیح
> : <float.hتعريف ثابتهايي از نوع شناور
پیوست Bدر کتاب K & Rاين کتابخانه ها را با جزئیات بیشتر توضیح مي دهد.
176/322 محیط برنامه سازی لینوکس
/* include headers of library */
/* defined for all routines */
/* in the file */
>#include < stdio.h
>#include < string.h
/* prototyping of functions */
/* to allow type checks by */
/* the compiler */
()void main
}
;int n
;[char string]50
/* strcpy)a,b( copies string b into a */
/* defined via the stdio.h header */
;("strcpy)string, "Hello World
نشانوند ها همیشه توسط مقدار درفراخواني های تابع رد مي شوند .يعني کپي های محلي مقادير نشانوند ها از روالها عبور مي کنند .هر
تغییر در نشانوند ها بطور دروني در تابع فقط در کپي های محلي نشانوند ها ايجاد مي شود.
بمنظور تغییر ( يا تعريف ) نشانوند درفهرست نشانوند ،اين نشانوند بايد بعنوان يك آدرس عبور کند ( ،در نتیجه الزام Cبرای تغییر
نشانوند واقعي در روال فراخواني).
بعنوان يك مثال به تعويض دو عدد بین متغیرها توجه کنید ،ابتدا اجازه دهید آنچه اتفاق مي افتد را اگر متغیرها توسط مقدار عبور کنند
را با مثال نشان دهیم
>#include < stdio.h
()void main
} /* WRONG CODE */
;int a, b
;a = 5
;b = 7
;(printf)"From main: a = %d, b = %d\n", a, b
;(exchange)a, b
;(" printf)"Back in main:
;(printf)"a = %d, b = %d\n", a, b
{
;temp = a
;a = b
;b = temp
178/322 محیط برنامه سازی لینوکس
()void main
} /* RIGHT CODE */
;int a, b
;a = 5
;b = 7
;(printf)"From main: a = %d, b = %d\n", a, b
;(exchange)&a, &b
;(" printf)"Back in main:
;(printf)"a = %d, b = %d\n", a, b
{
;temp = *a
;*a = *b
;*b = temp
;(" printf)" From function exchange:
;(printf)"a = %d, b = %d\n", *a, *b
{
نشانوندهاي خط فرمان
اين يك تمرين استاندارد يونیکس برای اطلعات در مورد گذر از خط فرمان به برنامه به طور مستقیم از طريق استفاده از يك يابیشتر از
نشانوندهای خط فرمان است )switches( .سوئیچ ها نوعا برای تغییر رفتار برنامه ،ياتنظیم مقادير برخي پارامترهای ورودی استفاده مي
179/322 محیط برنامه سازی لینوکس
شود .شما تا کنون با چند مورد از اينها روبرو شده ايد .برای مثال ،فرمان « »lsفايلها را در فهرست جاری شما لیست مي کند.
ولي هنگامیکه سوئیچ -۱اضافه شود »ls -1 « ،يك فهرست طولني رادر عوض تولید مي کند .به طور مشابه « »ls -1 -aيك فهرست
طولني ،شامل فايلهای پنهان راتولید مي کند .فرمان « »tail -20و ۲۰خط آخر فايل را ( به جای مقدار پیش فرض ) ۱۰چاپ مي
کند ،و مانند آن .
به طور فرضي ،سوئیج ها بسیار شبیه نشانوندهای توابع در Cرفتار مي کنند .و آنها از برنامه Cاز سیستم عامل عبور مي کنند .دقیقا با
) mainدر برنامه های ما هیچ چیزی بین پرانتز ها نداشته. همان روشي که نشاوندها بین توابع عبور مي کنند .تا کنون ،دستورات (
بنابراين ،يونیکس واقعا برای برنامه ها (هنگامیکه برنامه نويس انتخاب مي کند که از اطلعات استفاده کنديا نه ) دو نشانوند برای main
رافراهم مي سازد.
يك آرايه از رشته های کاراکتری ،که بطور مرسوم argvنامیده مي شود و يك صحیح ،که معمول argvنام دارد .که تعداد رشته های
آرايه رامشخص مي کند .دستور کامل خط اول برنامه عبارتست از:
(main ) integer ,char** argv
( نحو char**argvمشخص مي کند argvبايد اشاره گری به اشاره گر کاراکتر باشد ،که آن ،اشاره گری است به آرايه کاراکتر ( يك
رشته کارکتری ) از لحاظ کلمات ،يك آرايه از رشته های کاراکتری .شما همچنین مي توانید آن را به صورت ( ) chat*argvبنويسید
به هرحال خیلي در مورد جزئیات نحو آن نگران نباشید .کاربرد آرايه در زير واضح تر خواهد شد) .
هنگامیکه شما يك برنامه را اجرا مي کنید ،آرايه argvشامل همه اطلعات خط فرمان ،هنگامیکه شما فرماني را وارد کرديد مي شود۰ .
رشته ها با فضای سفید مشخص مي شوند) شامل خود فرمان صحیح argvتعداد کل رشته ها را مي دهد ،بنابراين برابر است با تعداد
a.out -iراتايپ کنید برنامه مقادير زير را دريافت مي کند. نشانوندها به اضافه يك .برای مثال اگر شما 2 -g -x 3 q
argc = 7
"argv]0[ = "a.out
"argv]1[ = "-i
"argv]2[ = "2
"argv]3[ = "-g
"argv]4[ = "-x
"argv]5[ = "3
"argv]6[ = "4
دقت کنید که نشانوندها ،حتي مقادير عددی ،در اين مورد رشته هستند .اين وظیفه برنامه نويس است که آنها را کد گشايي کرده و
تصمیم بگیرد با آنها چه بکند.
برنامه زير بطور ساده نام و نشانوندهايش را چاپ مي کند.
>#include < stdio.h
برنامه نويسان يونیکس قرار دادهای مشخصي در مورد چگونگي تفسیر فهرست نشانوندها دارند .آنها اجباری نیستند بلکه برنامه شما را
بای استفاده و فهم ديگران آسانتر مي سازند .اول اينکه اصطلحات سوئیچ ها و کلیدها با کاراکتر « » -شروع مي شوند .اين باعث
مي شود که به آساني آنها را تشخیص دهید .سپس ۷بسته به سوئیچ ،نشانوندها ممکن است شامل اطلعاتي که بعنوان صحیح ،شناور يا
فقط بعنوان يك رشته کاراکتری نگه داشته شده اند تفسیر شوند .با اين قرار دادها ،رايجترين راه تجزيه فهرست نشانوند بوسیله حلقه
Forو يك دستور switchمي باشد.
مانند زير:
>#include < stdio.h
>#include < stdlib.h
;int i
} ([switch )argv]i[]1
{
{
{
دقت کنید که [ argv ]i[ ]jيعني jامین کاراکتر iامین کاراکتری دستور ifراهنمای " ( ”-کاراکتر ) 0را بررسي مي کند .سپس دستور
switchامکان تغییرهای گوناگون عملیاتي که بسته به کاراکتر بعدی در رشته گرفته مي شوند را مي دهد ( .اينجا کاراکتر )
دقت کنید که استفاده از [ argv]++iبرای افزايش iقبل از استفاده ،اجازه مي دهد به رشته بعدی در يك دستور فشرده تکي دستیابي
داشته باشیم .توابع atoiو atofدر stdlib.hتعريف شده اند.
آنها از رشته های کاراکتری به ترتیب به صحیح ( )intsو مضاعف ( )doublesتبديل مي کنند.
يك خط فرمان تايپ شده ممکن است چنین باشد:
a.out -a 3 -b 5.6 -c “I am a string” -d 222 111
( کاربرد دبل کوتیشن ('') با -cدر اينجا اطمینان مي دهد که پوسته با رشته کامل سرو کار داشته ،شامل فاصله ها ،بعنوان يك شي
منفرد)
با قرارد دادی خطوط پیچیده فرمان مي توانند در اين روش بکار روند .سر انجام ،در اينجا يك برنامه ساده چگونگي جای دادن
دستورات تجزيه شده در تابع مجزا که هدف آن خط فرمان و تنظیم مقادير نشانوندهايش مي باشد را نشان مي دهد.
/********************************/
*/ */
/* Getting arguments from */
*/ */
/* the Command Line */
*/ */
/********************************/
}
int i;
if )argv]i[]0[ == '-'( }
switch )argv]i[]1[( }
default: fprintf)stderr,
"Unknown switch %s\n", argv]i[(;
{
{
{
{
int a = 0;
float b = 0.0;
ولي هنوز مي خواهید برنامه شما قادر به تغییر مقادير متغیرهای مشخص،فرض کنید شما نمي خواهید با تفسیر خط فرمان مواجه شويد
183/322 محیط برنامه سازی لینوکس
در يك روش محاوره ای باشد .شما مي توانید برنامه را در يك سری خطوط ـ printf/scanfبرای امتحان کاربرد در مورد اولويت
هايشان ساده کنید.
.
.
.
;(" printf)"Please enter the value of n:
;(scanf)"%d", &n
.
.
.
ومانند آن ،البته اين کار خوبي نخواهد بود اگر برنامه شما به عنوان بخشي از خط لوله ( )pipelineيا پايپ لين استفاده مي شود .برای
مثال استفاده از برنامه گرافیکي ، plot – dataچون پرسشها و پاسخها در جريان داده ها مخلوط مي شوند.
رفتار درست استفاده از يك واسط گرافیگي ساده است که يك جعبه محاوره تولید کند ،اختیار پارمترهای گوناگون کلید در برنامه را به
شما مي دهد .بسته های گرافیکي ما تعدادی از ابزارهای آسان برای استفاده از ساختارها و جعبه های مشابه را فراهم مي کند.
ساده ترين راه برای ست کردن متغیر صحیح nو متغیر شناور ( xيعني برای اجرای يك اثر مانند خطوط کد بال ) استفاده از جعبه
محاوره مانند زير مي باشد:
/* Simple program to illustrate use of a dialog box */
()main
}
/* Define default values: */
;int n = 0
;float x = 0.0
;(create_int_dialog_entry)"n", &n
;(create_float_dialog_entry)"x", &x
/* Create window with name "Setup" and top-left corner at )0,0( */
;(set_up_dialog)"Setup", 0, 0
;()read_dialog_window
184/322 محیط برنامه سازی لینوکس
اين برنامه را با استفاده از نام مستعار cgfxبرای پیوند در همه کتابخانه های لزم ترجمه کنید .
دو خط createمدخلهای جعبه و متغیرهای وابسته به آنها را تعريف مي کند set- up – dialog .جعبه ها را نام گذاری کرده و مکان
آنها را تعريف مي کند .سر انجام read- dialog-window ،پنجره را بال پرانده ( باز مي کند) و به شما اجازه تغییر مقادير متغیرها را
مي دهد.
هنگامیکه برنامه اجرا مي شود ،شما جعبه ای مشابه زير را خواهید ديد.
شكل
اعداد نشان داده شده را تغییر داده OK ،را فشار دهید ( .يا فقط کلید Enterرا بزنید).
تغییرات انجام مي شود .همه آنها به همین صورت است .بیشترين فايده اين مورد اينست که آن مستقل از روند داده ها از طريق
stdin/dstoutعمل مي کند .بطور کلي ،شما مي توانید حتي عملیات هر مرحله را در پايپ لين بسیاری از فرمانهای زنجیره ای با
استفاده از يك جعبه محاوره برای هر کدام کنترل کنید .
185/322 محیط برنامه سازی لینوکس
فصل هفتم : ورودی خروجی استاندارد
تاکنون ما از ابزار موجود برای ساخت ابزار جديد استفاده کرديم ،اما محدود به اين هستیم که به طور معقول با شل sed ،و awkچه
ميتوان انجام داد .در اين فصل ما قصد داريم ،برخي از برنامههای ساده را به زبان برنامهنويسي Cبنويسیم .فلسفه اصلي ساختن چیزها
اين است که همکاری تا نفوذ بر بحث و بررسي و طرح برنامهها ادامه يابد ـ ما ميخواهیم ابزاری را بوجود آوريم که ديگران بتوانند
استفاده کنند و به آنها اعتماد داشته باشند .در هر مورد ،ما سعي ميکنیم که يك استراتژی تحقق مناسب را نیز انجام دهیم :آغاز با
حداقل میزان ،که کار مفیدی را انجام دهد ،سپس افزودن ويژگيها و انتخابها (فقط) اگر مورد نیاز باشند.
دليل خوبي برای نوشتن برنامههای جديد از حافظه وجود دارند .ميتواند به اين دلیل باشد که مشکل موجود نميتواند فقط با
برنامههای موجود حل شود .اين مورد اغلب زماني صحیح است که برنامه بايد به فايلهای غیر مبتني بپردازد .برای مثال ـ اکثر
برنامههايي که ما تاکنون نشان دادهايم .حقیقتا ً فقط بر روی اطلعات متني به خوبي کار ميکنند .و يا ممکن است دستیابي به توان يا
سودمندی مناسب با شل و ساير ابزارهای دارای هدف کلي ،بسیار دشوار باشد .در چنین مواردی ،يك نسخه شل ميتواند برای
اختصاص به تعريف و واسط کاربر از يك برنامه خوب باشد 0و اگر به خوبي کار کند ،نیازی به انجام مجدد آن نیست) .برنامه zapاز
فصل آخر .مثال خوبي است :ابن برنامه فقط به چند دقیقه زمان برای نوشتن اولین نسخه در شل نیاز دارد و نسخه نهايي دارای يك
واسط کاربر مناسب ميباشد ،اما بسیار کند ميباشد.
ما به زبان Cخواهیم نوشت ،چون Cيك زبان استاندارد از سیستمهای يونیکس ميباشد ـ کرنل و همه برنامههای کاربر به زبان C
نوشته ميشوند ـ و حقیقتاً از هیچ زبان ديگری ،تقريباً به اين خوبي حمايت نميشود .ما فرض ميکنیم که شما زبان Cرا ميشناسید ،
حداقل تا اندازهای که آن را بخوانید .اگر اين اينگونه نیست ،زبان برنامهنويسي Cرا که نوشته . W.Bکرنیگمان و M.Dريتچای
ميباشد .مطالعه کنید (پرنتیك ـ مال .)1978
ما همچنین از کتابخانه استاندارد I / Oاستفاده خواهیم کرد ،يك مجموعه از زيربرنامههايي که خدمات موثر و قابل انتقال سیستم و I /
Oرا برای برنامههای Cفراهم ميکند.
کتابخانه استاندارد I / Oدر همه سیستمهای غیر يونیکس که از Cحمايت ميکنند ،در دسترس ميباشد ،بنابراين ،برنامههايي که برهم
کنشهای سیستم خود را برای تسهیلت آن محدود ميکنند ،ميتوانند به سهولت انتقال يابند.
مثالهايي که ما برای اين فصل انتخاب کردهايم ،دارای يك ويژگي مشترك ميباشند :آنها ابزار کوچکي هستند که ما از آنها به طور
منظم استفاده ميکنیم ،اما بخشي از ويرايش هفتم نبودند .اگر سیستم شما دارای برنامههای مشابه باشد ،شما ميتوانید از آن به عنوان
يك آگاه کننده برای مقايسه طرحها استفاده کنید .و اگر آنها برای شما جديد باشند ،شما آنها را به عنوان ابزاری مفید مييابید .در هر
حال ،آنها بايد در روشن کردن اين نکته که هیچ سیستمي کامل نیست و اينکه اغلب توسعه دادن چیزها و فائق آمدن بر کمبودها با
تلش نه چندان زياد آسان است ،به شما کمك کنند.
1ت 7 ت ورودي و خروجي استانداردvis :
بسیاری از برنامهها ،فقط يك ورودی را ميخوانند و يك خروجي را مينويسند :برای چنین برنامههايي I / O ،که فقط از ورودی
ل مناسب باشد و تقريباً همیشه برای شروع کار ،کافي است .
استاندارد و خروجي استاندارد استفاده ميکند ،ميتواند کام ً
اکنون اين مورد را با يك برنامه با عنوان visشرح ميدهیم که ورودی استاندارد خود را برای خروجي استاندارد خود کپي ميکند ،به
186/322 محیط برنامه سازی لینوکس
استثنای اينکه اين برنامه ،همه کاراکترهای غیرچاپي را با چاپ کردن آنها به صورت nnn 1مرئي ميسازد ،nnn ،ارزش هشت هشتي
کاراکتر ميباشد Vis .برای آشکارسازی کاراکترهای عجیب يا کاراکترهای ناخواسته که ممکن است درون فايلها نفوذ کرده باشند،
بيارزش ميباشد .برای نمونه ، vis ،هر پس برد را به صورت 1010پرينت ميکند که ارزش هشت هشتي کاراکتر پس برد ميباشد :
cat x $
a b c
$ vis sx
a b c \ 01010101010 - - -
$
برای پويش فايلهای متعدد با اين نسخه ابتدايي از ، visشما ميتوانید از catبرای جمع کردن فايلها استفاده کنید :
$ cat file1 file 2 … ?| vis
……
$ cat file1 file 2 … | vis | grep′ \ \ ′
و در نتیجه از يادگیری چگونگي دستیابي به فايلها از يك برنامه اجتناب کنید.
در ضمن ،بايد مشاهده شود که شما ميتوانید اين کار را با sedانجام دهید .چون فرمان ‘ ، ’lکاراکترهای غیر قابلچاپ را در يك شکل
قابل فهم آشکار ميسازد :
$ sed - n 1 x
abc <<<---
$
ل واضحتر از visميباشد .اما sedهرگز برای فايلهای غیرمتني معني نميدهد:
خروجي .sedاحتما ً
$ sed - n | / usr / you / bin
$ ! Nothing at all
(اين برنامه بر روی يك PDP – 11قرار دارد ؛ روی يك سیستم VAXو sedخاموش ميشود ،احتمال ً به دلیل اينکه ورودی شبیه
يك سطر خیلي طولني از متن به نظر ميرسد).
بنابراين sedنامناسب است و ما مجبور هستیم که يك برنامه جديد بنويسیم .سادهترين برنامههای کار ورودی و خروجي getchar ،و
putcharنامیده ميشوند .هر فراخواني برای ،getcharکاراکتر بعدی را از ورودی استاندارد ميگیرد ،که ممکن است يك فايل يا يك
لوله و يا يك پايانه (پیش فرض) باشد ـ برنامه ،نميداند که کدام يك ميباشد ـ متشابها ً ، )putchar ) Cکاراکتر Cرا روی خروجي
استاندارد قرار ميدهد که بر طبق پیش فرض ،نیز يك پايانه ميباشد.
تابع ، )print f )3تبديل فرمت خروجي را انجام ميدهد .فراخوانيهای printfو putcharميتوانند در هر ترتیبي ،يکي در میان
شوند؛ خروجي ،در ترتیب فراخوانيها آشکار ميشود .يك تابع ديگر با عنوان )scan f )3برای تبديل فرمت ورودی وجود دارد؛ اين
تابع ورودی استاندارد را ميخواند و آنها را به رشتهها ،اعداد و غیره در جايي که لزم ميباشد ،تجزيه ميکند .فراخواني ها برای
scanfو getcharنیز ميتوانند ،با هم مخلوط شوند.
در اين جا اولین نسخه visعبارت است از :
/ * vis : make funny characters visible )version \( * /
# include < stdio . hs
# include < stype. hs
) main (
}
187/322 محیط برنامه سازی لینوکس
; int c
while (( ) )) ) = getchar (! = EOF
if )isascii ) c ( $$
| | ) isprint ) c( | | c = = ′ \ n ′ c = = ′ \ t′ | | ′ (( ′
; ( put char ) c
else
; (print f ) ″ \ \ % ‘ 30 ″ , c
; ( ) exit
°
{
، get charبايت بعدی يا ارزش EOFرا از ورودی ،بر ميگرداند ،زماني که به پايان فايل (يا به يك اشتباه) برخورد ميکند .در ضمن،
EOFيك بايت از فايل نميباشد؛ بحث و بررسي مربوط به پايان فايل را در فصل 2به خاطر بیاوريد .ارزش EOFبه گونهای متفاوت
از هر ارزشي که در يك بايت تنها رخ ميدهد ،تضمین ميشود ،بنابراين ،میتواند متمايز از دادههای واقعي باشد ؛ Cبه صورت int
اعلن ميشود و نه .charبنابراين ،به اندازه کافي برای حفظ ارزش EOFبزرگ ميباشد .سطر
# > include < stdio.h
بايد در آغاز هر فايل مبدأ ظاهر شود .اين سطر باعث ميشود که کامپايلر ،يك فايل عنوان
( )usr / include / stadio.h/از برنامههای کاری استاندارد و سمبلهايي را بخواند که شامل تعريف EOFميباشند .ما از > stadio.
< hبه عنوان يك صورت مختصر برای اسم کامل فايل در متن استفاده ميکنیم.
فاي ل > . < ctype . hفايل عنوان ديگری د ر usr / include /ميباشد که آزمونهای وابسته به ماشین را برای تعیین ويژگیهای
کاراکترها تعريف ميکن .ما در اينجا از isasciiو ، isprintبرای تعیین اينکه آيا کاراکتر ورودی ( Ascll ،يعني دارای ارزش کمتر از
)0200و قابل چاپ ميباشد يا نه ،استفاده کرديم؛ ساير آزمونها در جدول 1ـ 6فهرستوار بیان ميشوند .توجه داشته باشید که سطر
جديد جدولبندی و فاصله ،توسط تعاريف موجود در > < ctype . bقابل چاپ نیستند.
فراخواني exitدر انتهای ،visبرای انجام کار برنامه به طور صحیح ،ضروری نیست ،اما اطمینان ميدهد که هر شماره گیرنده از برنامه با
يك وضعیت خروج نرمال (به صورت قراردادی صفر) از برنامه مواجه ميشود زماني که کامل ميشود يك روش ديگر برای بازگرداندن
وضعیت ،خارج شدن از mainبا return oميباشند ارزش بازگشت از ،mainوضعیت خروج برنامه ميباشد .اگر returnيا exitبه
صورت آشکار وجود نداشته باشد ،وضعیت خروج ،غیر قابل پیشبیني است.
برای کامپايل کردن يك برنامه ، Cمبدأ را در فايلي قرار دهید که نام آن با .Cپايان مييابد ،مانند ، vix.cآن را با ccکامپايل کنید،
سپس نتیجه را اجرا کنید که به اين صورت کامپايلر در يك فايل با عنوان a.outباقي ميماند ’a‘ ( .برای اسمبلر ميباشد) :
تمرين 1ت .6ما تصميم گرفتيم كه جدولبنديها بايد كنار گذاشته شوند ،به جاي اينكه به
صورت \ tيا يا \ 011آشكار شوند ،چون استفاده مهم ما از ، visپيدا كردن كاراكترهاي
حقيقتاً نامبهم ميباشد تتت تجدولبنديها ،ت غيرتصويريها ،فاصلهها در انتهاي سطرها تو
غيره Vis .را به گونهاي تغيير دهيد كه كاراكترهايي شبيه جدولبندي ،پس كج خط ،پس
برد ،كاغذ ت خورد و غيره ،در اجراهاي قراردادي cخود \ t ، \ \ ، \ b ، \ fو غيره .پرينت
شوندت توت تدرت تنتيجهت تفاصلههاي تخاليت تدرت تانتهايت تسطرهات تعلمتگذاري تشوند .آيات تشما
ميتوانيد چنين كاري را بدون ابهام انجام دهيد؟ طرح خود را با sed - n 1 $مقايسه كنيد.
تمرين 2ـ Vis .6را به گونهای تغییردهید که سطرهای بلند را در طول معقول تاکند .اين کار چگونه با خروجي غیر مبهم مورد نیاز در
تمرين قبلي برهم کنش ميکند؟
، argvت تيكت تاشارهگرت تبهت تآرايهايت تاستت تكهت تعناصرت تمنفردت تآنت تاشارهگرهاييت تبهت تآرايههاي
كاراكترها تمي تباشند؛ت هر تآرايه،ت تبات تكاراكترت NULازت )Ascll )′10 ′پايان تميپذيرد ،تبنابراين
ميتواند به صورت يك رشته عمل كند .اين نسخه ازت ، visبا كنترل اينكه آيا يك آرگومان
وجود دارد يا نه و آيا – sميباشد يا نه ،آغاز ميكند.
(آرگومانهای غیر معتبر ناديده گرفته ميشوند) .تابع ( ، strcmp )3دو رشته را مقايسه ميکند ،و اگر آنها شبیه به هم باشند ،صفر را بر
ميگرداند.
جدول 2ـ . 6يك مجموعه از تابعها را با استفاده کلي و به کارگیری رشته ،فهرستبندی ميکند ،که يکي از آنهاه strmpميباد.
معمول ً استفاده از اين تابعها ،به جای نوشتن تابعهای خود ،بهترين راه مي باشد ،چون آنها استاندارد هستند ،آنها بدون خطا هستند و
آنها اغلب سريعتر از چیزی هستند که شما خودتان ميتوانید بنويسید ،چون آنها برای ماشینهای خاص ،مطلوب شدهاند (گاهي اوقات
،با نوشته شدن در زمان اسمبلي مطلوب ميباشند).
190/322 محیط برنامه سازی لینوکس
تمرين 3ـ . 6آرگومان – sرا به گونهای تغییر دهید که vis – snفقط رشتههای nيا کاراکترهای پیاپي قابل چاپ را پرينت کند،
کاراکترهای غیرچاپي را حذف کند و توالیهای کاراکترهای قابل چاپ را کوتاه کند .چنین چیزی برای جدا کردن بخشهای بعدی
فايلهای غیر متني مانند برنامههای قابل اجرا ارزشمند ميباشد .بر فراز نسخههای سیستم ،يك برنامه stringرا تهیه ميکنند که چنین
کاری را انجام ميدهد .آيا داشتن يك برنامه مجزا يا يك آرگمان برای visبهتر است.
تمرين 4ـ .6در دسترس بودن کد مبدأ cيکي از نقاط قوت سیستم يونیکس ميباشد ـ کد ،راهحلهای ظريف را برای بسیاری از
مشکلت برنامهنويسي شرح ميدهد .موازنة بین قابلیت خوانده شدن مبدأ cو بهینه سازی اتفاقي دست آمده از نوشتن مجدد به زبان
اسمبلي را شرح دهید.
آنها ثابتها هستند و نه متغیرها ،بنابراين شما نميتوانید ،به آنها استناد کنید.
، ) ( getcharهمانند )getc )stdinمیباشد و ) putchar )cهمانند )putc c , stdoutميباشد .در حقیقت ،هر چهار تابع ،به عنوان
> < stdio . hتعريف ميشوند ،چون آنها با اجتناب از
يك يك تابع برای هر کاراکتر ،سريعتر اجرا ميکنند .به جدول 3ـ 6برای ساير تعاريف در
> <stdio . hمراجعه کنید.
با برخي از مقدمات خارج از روش ،اکنون ما ميتوانیم سومین نسخه از vicرا بنويسیم .اگر آرگومانهای سطر فرمان وجود داشته
باشند ،آنها به ترتیب پردازش ميشوند .اگر آرگومانها وجود نداشته باشند ،ورودی استاندارد پردازش ميشود.
/ * vis : make funny characters visible )version 3( * /
; (exit )0
{
اين رمز ،بر اين قرارداد تکیه دارد که آرگومانهای اختیاری در ابتدا ميآيند .پس از اينکه هر آرگومان اختیاری ،پردازش ميشود argc ،و
argvتنظیم ميشوند ،در نتیجه مابقي برنامه ،وابسته به حضور آن آرگومان نميباشد .اگرچه ،visفقط انتخاب تنها را تشخیص ميدهد،
اما ما رمز را به صورت يك حلقه برای نشان دادن راه برای تشخیص پردازش آرگومان نوشتیم .در فصل 1ما روش نامقطعي را که بر
طبق آن برنامههای يونیکس از آرگومانهای انتخابي استفاده ميکردند توضیح داديم .جدای از يك میل برای بينظمي ،يکي از دليل آن ،
اين است که نوشتن رمز برای استفاده از بخش آرگومان برای هر تغییر ،به طور بديهي آسان نميباشد .تابع ( get opt )3که بر روی
برخي از سیستمها يافت ميشود .يك تلش برای توجیه کردن موقعیت ميباشد؛ شما بايد قبل از نوشتن برنامه خود ،به تحقق در مورد
آن بپردازيد.
برنامه کار ، risيك فايل منفرد را پرينت ميکند :
vis )fp( / * make chars visible in FILE * fp * /
; FILE * Fp
}
; int c
(while )) c = get c )fp( ! = EOF
if )isaciicc( $$
) isprint )c ( | | c = = ′ \n | | c = = ′ \ t′ / | c = = ′ (( ′
; ( put cahr ) c
(elw if ) ! strip
; ( printf ) ″ \ \ % 30 ″ , c
{
تابع fprintfمشابهه با printfميباشد ،به جز برای يك آرگومان نشانگر فايل ،که فايلي را که بايد نوشته شود مشخص ميکند.
تابع ،fcloseارتباط بین اشارهگر فايل و نام خروجي را که توسط Fopenتعیین شد ،از بین ميبرد و اشارهگر فايل را برای فايل ديگر
آزاد ميکند .چون يك محدوديت بر روی تعداد فايلهايي (حدود )20وجود دارد که يك برنامه ميتواند به طور همزمان باز کند ،در
نتیجه ،بهترين کار ،آزاد کردن فايلها در زماني است که ديگر به آنها نیازی نیست .در حالت عادی ،خروجي تهیه شده با هر کدام از
تابعهای کتابخانه استاندارد ،مانند printf ، putcو غیره ،میانگیر ميسازد ،و در نتیجه ميتواند به منظور موثر بودن ،در chunkهای
بزرگ نوشته شود ( .در اينجا استثنا ،خروجي برای يك پايانه ميباشد ،که معمول ً در همان زماني که تولید ميشود ،نوشته ميشود و يا
حداقل ،زماني که سطر جديد پرينت ميشود) .فراخواني fcloseبر روی يك فايل خروجي نیز هرگونه خروجي میانگیر شده را خارج
ميکند Fclose .نیز به طور خودکار برای هر فايل باز ،فراخوان ميشود زماني که يك برنامه exit ،را فرا ميخواند و يا ازـ main
برميگردد.
،Stderrبه کل برنامه تخصیص داده ميشود به همان روشي که stdinو stdoutتخصیص داده ميشوند .خروجي نوشته شده بر روی
stdderبر روی پايانه کاربر ظاهر ميشود ،حتي اگر خروجي استاندارد مجدداً جهتيابي شود ،Vis .تشخیص خود را بر روی stderr
به جای stdoutمينويسد ،بنابراين اگر يکي از فايلها نتواند به دلیلي دستیابي شود ،پیغام راه خود را به سمت پايانه کاربر به جای ناپديد
شدن درون خط لولهای يا درون يك فايل خروجي ،پیدا ميکند( .خطای استاندارد ،اندکي پس از لولهها ،اختراع شد ،پس از اينکه
194/322 محیط برنامه سازی لینوکس
تمرين 5ـ .6يك برنامه pritableبنويسید که نام هر فايل آرگومان را که شامل فقط کاراکترهای قابل چاپ ميباشد ،پرينت کند؛ اگر
فايل شامل کاراکتر غیر قابل چاپ باشد ،اسم آن پرينت نشود Printable .در موقعیتهايي مانند اين ،مفید است :
$ pr ′ printable * ′ | pr
انتخاب 7ـ را برای معکوس کردن حس آزمون ،همانند grepوارد کنید.
Printableچه بايد انجام دهد اگر آرگومانهای اسم فايل وجود نداشته باشند؟ printableبه چه وضعیتي بايد برگردد؟
شده است .بنابراين ،مثال بعدي ما برنامهاي با عنوان Pميباشد كه يك فايل پرده پر را در
يك زمان پرينت ميكند و منتظر جواب از كاربر ،پس از هر پرده نمايش و قبل از رفتن به
پرينت بعدي ،ميماند ، ″P″( .يك اسم كوتاه و مناسب براي برنامهاي است كه ما آن را
بسيار زياد استفاده ميكنيم).
همانند ساير برنامهها p ،از فايلهای نامگذاری شده به عنوان آرگومانها ويا از ورودی استاندارد خود ميخواند :
$ p vis . c
…
$ grep ′ # define ′ * . ] ch [ | p
…
$
اين برنامه ،به بهترني نحو در زبان cنوشته ميشود ،چون اين برنامه در زبان cآسان است و در زبانهای ديگر دشوار است؛ ابزار
استاندارد ،در ترکیب کردن ورودی از يك فايل يا لوله با ورودی پايانه ،مناسب نیستند.
طرح اساسي و بي پيرايه ،چاپ كردن ورودي در قطعههاي كوچك ميباشد .يك اندازه
مناسب براي قطعه،ت 22سطر ميباشدت :كه اين اندازه ،اندكي كمتر از پرده نمايشت 24
1
تتازت تيكت تصفحهت تاستاندارد ت 66سطري 3 سطريت تاكثرت تپايانههايت تتصويريت تميباشدت تو ت
ميباشد .يك روش ساده تبراي اينكهت pبه كاربر پيامواره تبدهد ،چاپنكردن آخرين سطر
جديد از هر قطعه 22سطري ميباشد .بنابراين ،مكان نما در انتهاي راست هر سطر به
جاي حاشيه چپ ،مكث ميكند .زماني كه كاربر كليدت RETURNرا فشار ميدهد .سطر
جديد مفقود را ذخيره ميكند و بنابراين باعث ميشود كه سطر بعدي در مكان صحيح
خود تآشكار تشود .اگرت تكاربر،ت ctl-dيات gرات تدرت تانتهاي تيك تپرده تنمايش تتايپ تكند،ت pبوجود
ميآيد.
ما عملکردهای خاصي را برای سطرهای طولني انجام نميدهیم ما همچنین درخصوص فايلهای متعدد نگران نیستیم :ما صرفا ً بدون
توضیح از يك فايل به فايل ديگر جست ميزند ،به اين صورت رفتار
… p filenames $
t filenames … | pخواهد بود. شبیه به رفتار $
اگر نیاز به اسامي فايلها باشد ،آنها ميتوانند با يك حلقه Forبه صورت زير اضافه شوند :
… $ for i in filenames
> do
> echo $ i :
> cat $ I
> done | P
حقیقتاً ،ويژگیهای بسیار زيادی وجود دارند که ما ميتوانیم به اين برنامه اضافه کنیم .بهتر است که يك نسخه جدا شده بسازيم ،سپس
بگذاريم گسترش يابد ،به همان صورتي که تجربه پذيرفته میشود .به اين صورت ،ويژگیها از نوعي هستند که مردم حقیقتا ً طالب آنها
هستند و نه ويژگیهايي که ما فکر ميکنیم آنها ميخواهند.
ساختار اصلي ، Pهمانند visميباشد :زير برنامه اصلي ،درون فايلها تکرار ميشود و زير برنامه printرا که بر روی هر کدام از آنها
196/322 محیط برنامه سازی لینوکس
ما يك جفت از طرحهای ديگر را برای ،efopenقبل از فرو نشاندن بر روی اين برنامه ،بررسي کرديم .يکي از آنها ،قبل از چاپ کردن
پیام ،با يك اشارهگر تهي که خرابي و اشکال را نشان ميدهد ،آن را باز ميگرداند .چنین چیزی به شماره گیرنده انتخاب ادامه يا خروج
را ميدهد .طرحي ديگر efopen ،را با سهآرگومان تهیه ميکند و اين آرگومانها مشخص ميکنند که آيا بايد پس از شکست در باز
کردن فايل بازگشت يا خیر .اما در اکثر مثالهای ما ،اشارهای برای ادامه وجود ندارد ،اگر نتوان به يك فايل دست يافت ،بنابراين نسخه
197/322 محیط برنامه سازی لینوکس
} else
;buf ] strlen )buf( –1[ ′ \ 0 ′
; (fputs )buf , stdout
; (fflush )stdout
; ( ) ttyin
; lines = 0
{
{
ما از BUFSIZاستفاده کرديم ،که در > ، < stdio . hبه عنوان اندازه میانگیر ورودی تعريف ميشود ، buf , size , fp( fgets( .سطر
بعدی ورودی را از fpتا يك سطر جديد واکشي ميکند و سطر جديد را درون bufقرار ميدهد و يك \ 0پايان دهنده اضافه ميکند؛
بیشتر ،کاراکترهای اندازه ، 1کپي ميشوند BUFSIZ , NULL .را در انتهای فايل باز ميگرداند fgets( .مي”وند بهتر طراحي شود :
fgetsبه جای يك تعداد کاراکتر buf ،را باز ميگرداند؛ به علوه ،هیچ اخطاری نميدهد ،اگر خط ورودی خیلي طولني باشد .هیچ
کدام از کاراکترها مفقود نميشوند ،اما شما بايد برای مشاهده اينکه واقعا چه اتفاقي ميافتد به bufنگاه کنید).
تابع ،strlenطول يك رشته را باز ميگرداند؛ ما از آن برای اين منظور استفاده ميکنیم که سطر جديد پسین ،آخرين سطر ورودی را
حذف کنیم ، )F puts )buf , fp .رشته bufرا روی فايل fpمينويسد .فراخواني ff lushدر پايان صفحه ،هر گونه خروجي میانگیر
شده را خارج ميکند.
وظیفه خواندن پاسخ از کاربر ،پس اينکه هر صفحه پرينت شد ،به يك زيربرنامه با عنوان ttyinفرستاده ميشود Ttyin .نميتواند
ورودی استاندارد را بخواند ،چون pبايد کار کند حتي زماني که ورودی آن از يك فايل يا از يك لوله ميآيد .برای بکارگیری آن،
برنامه ،فايل dev / tty /را باز ميکند ،که پايانه کاربر ،بدون توجه به هر گونه جهتدهي مجدد ورودی استاندارد ،ميباشد.
ما ttyinرا برای بازگرداندن اولین کاراکتر از پاسخ نوشتیم ،اما از آن ويژگي در اينجا استفاده نميشود.
ttyin ) ( / * process response from / dev / tty )version 1( * /
}
; [char buf ] BUFSIZE
; ( ) FILE * efopen
Static FILE * tty = NULL
اشارهگر فايل ،devttyبه صورت staticاظهار ميشود ،در نتیجه ارزش خود را از يك فراخوان از ttyinبه فراخوان بعدی نگه ميدارد؛
فايل ، dev / tty /فقط در اولین فراخوان باز ميشود.
به طور بديهي ويژگیهای ديگری وجود دارند که بايد بدون کار زياد ،به pاضافه شوند ،اما ارزشي ندارد که نسخه اول ما از اين برنامه،
کاری را انجام دهد که در اينجا توصیف ميشود 22 :سطر را پرينت کنید و منتظر بمانید .قبل از اينکه ساير چیزها اضافه شوند ،زمان
طولني بود و تا امروز فقط افراد کمي از اين ويژگيها استفاده ميکنند.
يك ويژگي اضافي آسان ،تعیین تعداد سطرها در هر صفحه ميباشد ،يك متغیر pagesizeکه ميتواند از سطر فرمان تنظیم شود :
… p -n $
قطعات را با nسطر ،پرينت ميکند .چنین چیزی فقط مستلزم اضافه کردن يك رمز آشنا در آغاز mainميباشد :
/ * p : print input in chunks )rersion 2( * /
…
; int i , pagesize = pAGESIZE
; [programe = argv ]0
} ( if )argc > 1 $ $ argv ]1[ ]0[ = = ′ - ′
;( [pagesize = atoi ) $ argv ]1[ ]1
; argc - -
; argv + +
{
…
تابع atoiيك رشته کاراکتر را به يك عدد صحیح تبديل ميکند (به ( atoi )3مراجعه کنید).
افزايش ديگر به ، pتوانايي گريز به طور موقت ،در پايان هر صفحه برای انجام فرماني ديگر ميباشد .در مقايسه با edو بسیاری ديگر
از برنامهها ،اگر کاربر ،سطری را تايپ کند که با يك علمت تعجب آغاز ميشود ،مابقي سطر به عنوان يك فرمان تلقي ميشود و برای
اجرا از شل عبور ميکند .اين ويژگي نیز بي اهمیت است ،چون تابعي با عنوان ( system )3وجود دارد که اين کار را انجام ميدهد ،اما
توضیح زير را بخوانید .نسخه اصلح شده ،ttyinبه شرح زير است :
} ( ; ; ) for
if )fgets )buf , BUFSIZE , tty( = = NULL | | buf ]0[ = = ′q′
; (exit )0
} ( else if )buf ]0[ = = ′ ! ′
; (system )buf + 1 / * BUG here * /
; (printf ) ″ ! \ n ″
{
else / * ordinary line * /
; [return buf ]0
{
{
متأسفانه ،اين نسخه ازـ ttyinدارای يك خطای نامحسوس و خطرناك ميباشد .فرمان ،توسطـ systemاجرا ميشوند و ورودی
استاندارد را از pميگیرد ،بنابراين اگر ،pاز لوله يا يك فايل خوانده شود ،فرمان ميتواند با ورودی خودش ،تداخل کند :
$ cat / etc / passwd | p – 1
root : 3 D : f HR 5 KoB. 3 s : o : 1 : s . usr : / : ! ed edرا از pميگیرد
؟ etc / passwd … ed /را ميخواند
! … غلط است و از سیستم خارج ميشود
راه حل ،مستلزم آگاهي در اين خصوص ميباشد که چگونه فرآيندهای يونیکس کنترل ميشوند و ما آن را در بخش 4ـ 7ارائه
ميدهیم .در حال حاضر ،آگاه باشید که سیستم استادارد در کتابخانه ميتواند مشکل آفرين باشد ،اما ttyinبه درستي کار ميکند اگر با
نسخه systemدر فصل 7کامپايل شود.
ما اکنون دو برنامه نوشتهايم vis ،و pکه بايد متغیرهای ،catبا اندکي شاخ و برگ تلقي شوند .بنابراين ،آيا آنها بايد همگي بخشي از
catو قابل دستیابي توسط آرگومانهای اختیاری مانند – pو – vباشند؟ پرسش مربوط به اينکه آيا يك برنامه جديد بنويسیم يا
ويژگیها را به برنامه قبلي اضافه کنیم ،مکررا ً مطرح ميشود ،مادامي که افراد عقايد جديد دارند .ما يك پاسخ قطعي نداريم ،اما اصولي
وجود دارند که به تصمیمگیری در اين زمینه کمك ميکنند.
اصل مهم ،اين است که برنامه بايد فقط يك کار اصلي را انجام دهد ـ اگر کارهای زيادی را انجام دهد ،بزرگتر ،کندتر و سختتر قابل
نگهداری و سختتر قابل استفاده ميباشد .به راستي ،ويژگیها ،اغلب بدون استفاده ميمانند ،چون مردم نميتوانند انتخابها را به خاطر
بسپارند.
اين موضوع بیان ميکند که catو visنبايد ترکیب شوند Cat .فقط ورودی خودش را کپي ميکند ،بدون اينکه آن را تغییر دهد ،در
حالیکه visآن را منتقل ميکند .ترکیب آنها ،برنامهای ميسازد که دو چیز متفاوت را انجام ميدهند .اين حالت تقريبا ً با catو pنیز
آشکار ميباشد Cat .برای کپي کردن سريع وموثر معني ميدهد ،در حالیکه pبرای گرفتن اطلعات معني ميدهد .و pورودی خودش
را منتقل ميکند :هر سطر جديد بیست و دوم ،حذف ميشود .سه برنامه مجزا به نظر طرح صحیحي ميآيند.
تمرين 6ـ 6ـ آيا pبه طور معقول عمل ميکند اگر pagesizeمثبت نباشد؟
200/322 محیط برنامه سازی لینوکس
تمرين 7ـ 6ـ چه چیز ديگری ميتوان با pانجام داد؟ توانايي برای پرينت مجدد بخشهای ورودی قبلي را (اگر مناسب است) ارزيابي
و اجرا کنید( .اين يك ويژگي اضافي است که ما از آن استفاده ميکنیم) .يك مسیر ساده را برای مجاز کردن پرينت کمتر از يك پرده پر
از ورودی پس از هر وقفه ،اضافه کنید .يك مسیر ساده را برای پويش به طرف جلو يا به طرف عقب برای يك سطر مشخص شده
توسط عدد يا محتوا ،اضافه کنید.
تمرين 8ـ 6ـ از تواناييهای کار ـ گرداني فايل exesتوکار شل استفاده کنید (برای تثبیت فراخوان ttyinبا سیستم به )sh )1مراجعه
کنید).
تمرين 9ـ 6ـ اگر شما فراموش کنید که يك ورودی را برای pمشخص کنید p ،به آرامي منتظر ورودی از پايانه باقي ميماند .آيا
کشف اين خطای احتمالي ،ارزشمند است؟ اگر ارزشمند است؟ چگونه ؟ توجه )isutty )3 :
چه اتفاقي ميافتد اگر طرحـ egrepچیزی را تطبیق نکند؟ در اين حالت،ـ pickهیچ آرگوماني ندارد و شروع به خواندن ورودی
، zapدر يك روش گیج کننده ،خراب ميشود .نیاز به يك آرگومان آشکار ،يك روش آسان برای غیر
استاندارد خود ميکند؛ فرمان
مبهم کردن چنین موقعیتهايي ميباشد و قرارداد ’ـــ ‘ از catو ساير برنامهها ،نشان ميدهد که چگونه آن را تشخیص دهیم.
/ * pick : offer choice on each argument * /
> # include < stdio. h
char * programe ; / * program name for error message * /
pickبرای انتخاب آرگومانها به طور برهمکنشي يك مسیر ساده را در يك برنامه متمرکز ميکند .چنین چیزی نه تنها يك کار مفید را
فراهم ميکند ،بلکه همچنین نیاز به انتخابهای برهمکنشي را بر روی ساير فرمانها کاهش ميدهد.
6ت 6 ت روي خطاها و خطازدايي
ل يك برنامه نوشته باشید ،با تصور يك خطا آشنا هستید .راه حل خوبي برای نوشتن رمز بدون خطا وجود ندارد به جز اينکه
اگر شما قب ً
مراقب باشیم که يك طرح ساده و تمیز به وجود آوريد و آن را به دقت اجرا کنید و آن را تمیز نگه داريد ،همچنانکه آن را تغییر
ميدهید.
ابزار اندکي از يونیکس وجود دارند که به شما در پیدا کردن خطاها کمك ميکنند ،اگر چه هیچ کدام از آنها واقعا ً عالي نميباشند .اما
برای شرح آنها ،ما به يك خطا نیاز داريم و همه برنامههای موجود در اين کتاب کامل هستند .بنابراين ،ما يك خطای نمونه ايجاد
ميکنیم.
تابع ارائه شده pickدر بال ،را در نظر بگیريد .در اين جا نیز وجود دارد ،اما اکنون دارای يك خطا ميباشد( .نیازی نیست که دوباره آن
را از اول تکرار کنیم).
pick ) s( / * offer choice of s * /
; Char * s
}
; ( fprint ) ″ % s ? ″ , s
( if )ttyin ) ( = = ′ y ′
; ( print f ) ″ % s \ n ″ , s
{
202/322 محیط برنامه سازی لینوکس
“ ” memory faultبه اين معناست که برنامه شما سعي ميکند به بخشي از حافظه مراجعه کند
که مجاز نميباشد .معمول ً به اين معناست که يك اشارهگر ،به جايي نامعقول اشاره ميکند ، ”Bus error“ .تشخیصي ديگر با همین
معني ميباشد و اغلب با پويش کردن يك رشته پايان نیافته ،بوجود ميآيد.
“ ، ” cor dumpedبه اين معناست که کرنل ،وضعیت برنامه اجرا کنندة شما را در يك فايل با نام coreدر فهرست ذخیره ميکند.
شما همچنین ميتوانید يك برنامه را مجبور کنید که با تايپ ، \ctl – 1حافظه اصلي را خالي کند ،البته اگر در پیش زمینه اجرا ميشود
و يا با نرمال ، kill-3حافظه اصلي را خالي کنید ،البته اگر در پیش زمینه ميباشد.
دو برنامه برای نوشتن در حافظه وجود دارد adb ،و .sdbهمانند اکثر خطا زداها ،آنها مرموز ،پیچیده و ضروری هستند Adb .در
هفتمین ويرايش وجود دارد؛ sdbدر اکثر نسخههای اخیر سیستم در دسترس ميباشد .يکي از اين دو برنامه ،مطمئنا ً در سیستم وجود
دارند.
ما در اينجا فقط به حداقل استفاده قطعي از هر کدام از آنها ميپردازيم :پرينت کردن يك
، stack traceکه تابعي است که زماني اجرا شد که برنامه به پايان رسید ،تابعي که آن را فراخواند و مواردی از اين قبیل .اولین تابع
نامگذاری شده در ،stack traceدر جايي است که برنامه وجود داشت زماني که خاموش شد.
برای اجرای يك stack traceبا ، adbفرمان c $ ،ميباشد :
adb pick core $ به adbاستناد ميکند
c $ stack traceرا درخواست ميکند
) - stroutو 0و 011و )011200 01155772
adjust : °
fillch : 060542
( و 0و 011و doprnt ) 011200 01155722
(و f print f )0177345 011200
iop : 011200
fmt : 0177345
args : °
(pick )0177345
s: 0177345
(و main )0177234 035
argc : 035
argv : 0177234
i: 01
buf : °
ctl – d از سیستم خارج شويد
203/322 محیط برنامه سازی لینوکس
$
اين برنامه ،بیان ميکند کهـ main ، pickرا فراخواند ،که در نتیجه ـ fprintfرا فراخواند،ـ fprintf ، doprntـ را فراخواند و –
doprint ، - stroutرا فراخواند .چون – dopmtدر هیچ جايي در pick.cذکر نميشود ،در نتیجه مشکلت ما بايد جايي در fprintf
يا بالتر باشند( .سطرها پس از هر زيربرنامه درـ ، tracebackارزش متغیرهای محلي را نشان ميدهند c$ .اين اطلعات را حذف
ميکند ،همان کاری که c$خودش در برخي از نسخههای adbانجام ميدهد)
همه اين موارد ،همین مورد را با sdbبررسي ميکنیم : قبل
$ sdb pick core
warning : ′ a . out ′ not compiled with – g
.زير برنامه در جايي که برنامه به پايان ميرسد iseek : address oxa 64
* t stack traceرا درخواست ميکند
( ) isseek
(fprintf )54 91 47 47 21 540 61
( pick ) 54 91 47 47 21
( و 21 47 47 89 88و main ) 12 91 47 47 21 30
*q از سیستم خارج شويد
$
اطلعات به صورت متفاوت فرمت ميشوند ،اما يك موضوع عمومي وجود دارد:
fprintf . ) tracebackمتفاوت است چون بر روی يك ماشین متفاوت اجرا شد ــ 11/750ــ VAXـ که دارای يك پیادهسازی
متفاوت از کتابخانه استاندارد I / Oميباشد) .و مطمئناً ،اگر ما در نسخه خراب pickبه درخواست fprintfنگاه کنیم ،اشتباه است :
; ( f print f ) ″ % s ″ , s
stderrوجودت تندارد،ت تبنابراينت ترشتهت تفرمتت ، % s?″ت تبهت تعنوانت تيكت تاشارهگرت FILEاستفاده
ميشود و البته بينظمي رخ ميدهد.
ما اين خطا را پاك کرديم ،چون عمومي است ،يك نتیجه از بيتوجهي به جای طرح بد .همچنین اين امکان وجود دارد که خطاها را به
اين صورت پیدا کنیم ،که در آن يك تابع با آرگومانهای اشتباه و از طريق استفاده از ، )lint )1درستي سنجي ، cفراخوان ميشود.
Lintبه بررسي برنامههای cبه منظور يافتن خطاهای بالقوه ،مشکلت قابل حمل و ساختاهاری مشکوك ميپردازد .اگر ما lintرا روی
کل فايل pick.cاجرا کنیم ،خطا مشخص ميشود :
$ lint pick . c
……
(fprintf , arg . l used in consistently ″ llib – 1 c″ )69( : : ″ pick.c ″ )28
در ترجمه ،اين برنامه بیان ميکند که اولین آرگومان fprintfدر تعريف کتابخانه استاندارد ،از استفاده آن د ر 28سطر از برنامهها،
متفاوت ميباشد .اين يك تذکر قوی درباره چیزی مي باشد که اشتباه است.
، Lintيك موفقیت مرکب است Lint .دقیقا ً بیان ميکند که چه چیزی در اين برنامه اشتباه است ،اما همچنین تعداد زيادی از پیامهای
نامربوط را تولید ميکند که ما در بال حذف کرديم و مستلزم مقداری تجربه در اين خصوص ميباشد که بدانیم به چه چیزی توجه شود
و چه چیزی ناديده گرفته شود .اگر چه تلش ارزشمندی است ،چون lintبرخي از خطاهايي را پیدا ميکند که تقريباً غیرممکن است
204/322 محیط برنامه سازی لینوکس
افراد آنها را ببینند .اجرای lintپس از يك زماني طولني از ويرايش ،ارزشمند است و اطمینان ميدهد که شما هر اخطاری را که
ميدهد ،درك ميکنید.
; (exit ) 0
{
ما برنامه را برای استفاده از ps – agنوشتیم (انتخاب وابسته به سیستم ميباشد) ،اما شما ميتوانید فقط فرآيندهای خود را حذف کنید
مگر اينکه شما ابرکاربر باشید .اولین فراخوان برای ، fgetsسطر عنوان را از ، psپاك ميکند؛ اين يك عملکرد جالب برای استنتاج
چیزی است که اتفاق ميافتد ،اگر شما سعي کنید فرآيندی را که مطابق با آن سطر عنوان ميباشد ،حذف کنید .
تابع ، sscanfعضوی از خانواده )scanf )3برای انجام تبديل فرمت ورودی ميباشد .اين تابع ،از يك رشته تبديل ميشود به جای
اينکه از يك فايل تبديل شود.
فراخوان killاز سیستم ،علمت خاصي را به فرآيند ميفرستد ؛ علمت SI GKI LLکه در
> < signal. hتعريف ميشود و نميتواند متوقف شود و يا ناديده گرفته شود .شما ممکن است از فصل 5به خاطر آوريد که ارزش
عددی آن 9است .اما عملکرد بهتر ،استفاده از ثابتهای نمادی از فايلهای عنوان ميباشد ،به جای اينکه برنامههای خود را با اعداد
جادويي ،بیان کنید.
اگر هيچ آرگوماني وجود نداشته باشد zap ،هر سطر از ورودي Psرا براي انتخاب ممكن،
ارائهت تميدهد .اگرت تيكت تآرگومانت توجودت تداشتهت تباشد .درت تنتيجهت ، zapت تفقطت تسطرهايي تاز
خروجي psرا ارائه ميدهد كه آن را تطبيق كنند .تابع ( ،s1 , s2( strindexبررسي ميكند كه
آيا آرگومان ،بخشي از تيك سطر از خروجيت psرات تطبيق ميكند يا نه و تاين كار را با
استفاده از st rn cmpانجام ميدهد (جدول 2ت .)6
،Strindexموقعيت در s1را به جايي باز ميگرداند كه s2رخ ميدهد و يا به – 1باز ميگرداند،
اگر s2وجود نداشته باشد.
جدول 4ـ 6ـ تابعهايي را که عموماً استفاده ميشوند ،از کتابخانه استاندارد I / Oرا به طور خلصه بیان ميکند.
تمرين 11ـ 6ـ zapرا به گونهای تغییر دهید که هر تعداد از آرگومانها بتوانند ذخیره شوند .همانگونه که نوشته شد zap ،در حالت
عادی ،سطر را بر طبق خودش به عنوان يکي از انتخابها ،پژواك ميکند .آيا بايد اينگونه باشد؟ اگر نه ،برنامه را متعاقباً تغییر دهید :نکته
.)get pid )3 :
206/322 محیط برنامه سازی لینوکس
تمرين 12ـ 6ـ يك تابع )fgrep )1در اطراف strindexبسازيد .زمانهای اجرا برای جستجوهای پیچیده را با هم مقايسه کنید ،ده
کلمه را در يك سند بیان کنید .چرا fgrepسريعتر عمل ميکدن؟
)… , print f )fmt , al … , alرا بر طبق fmtفرمت ميکند و بر روی stoutپرينت ميکند
)… , fprint f )fp … را بر روی فايل fpپرينت ميکند
)… , sprintf )s … را درون رشته ،sپرينت ميکند
)fget s )s , n , fp حداکثر nکاراکتر را از ، fpدرون sميخواند
NULLرا در انتهای فايل باز ميگرداند.
)f puts )s , fp رشته sرا بر روی فايل fpپرينت ميکند
)f flush )fp هر گونه خروجي میانگیر شده ،بر روی فايل fpرا پاك ميکند
)f close )fp فايل fpرا ميبندد
)fp = popen )s , mode لوله را برای فرمان sباز ميکند Fopen .را مشاهده کنید
)pclose )fp لوله fpرا ميبندد
)system )s فرمان sرا اجرا ميکند و منتظر کامل شدن آن باقي ميماند
> ability
<? را انتخاب ميکند (>) کاربر اولین نسخه
idiff out put in file idiff . out
$ cat idiff . out خروجي در اين فايل قرار ميگیرد
this is
not a test
of
your
skill
and comprehesion
$
اگر بجای < يا > پاسخ eداده شود ،در نتیجه idiff ، ed ،را به دو گروه از سطرهايي که خوانده ميشوند ،استناد ميکند .اگر دومین
پاسخ eبوده باشد ،در نتیجه ،میانگیر ويراستار به اين صورت به نظر ميرسد :
your
skill
and comprehesion
……
our
ability
هر چیزی که درون فايل توسط edنوشته ميشود ،چیزی است که وارد خروجي نهايي ميشود.
در آخر ،هر فرماني ميتواند از طريق گريز با ! cmdدر idiffاجرا شود .از نظر تکنیکي ،سختترين قسمت کار diffميباشد و تاکنون
برای ما انجام شده است .بنابرای ،کار واقعي ،idiffتجزيه کردن خروجي diffو باز کردن ،بستن ،خواندن و نوشتن فايلهای صحیح در
زمان درست آن ميباشد .زير برنامه اصلي ،idiffفايلها را تنظیم ميکند و فرآيند diffرا اجرا ميکند :
/ * idiff : interactive diff * /
> # include < stdio . h
> # include < ctype . h
char ; * programe
# define HUGE 10000 / * large number of lines * /
آرگومان خود را روی هم، mktemp . متفاوت از هرگونه فايل موجود ميباشد، فايلي را بوجود ميآورد که نامش، mktemp )3( تابع
فايل، unlike )2( فراخوان سیستمـ. جايگزين ميشوند، و يك حرفidiff از فرآيندـprocess-id توسطـ، x’s ششـ: مينويسدـ
idiff توسط يك تابع با عنوان،diff کار حلقهسازی درون تغییرات گزارش شده توسط.نامگذاری شده را از سیستم فايل پاك ميکند
، از روی داده های ناخواسته در يك فايل بگذريد، را پرينت کنیدdiff يك قطعه از خروجي: عقیده اصلي ساده است.انجام ميشود
. جزئیات يکنواخت بسیار زيادی وجود دارد.سپس نسخه مطلوب از فايل ديگر را کپي کنید
. بسیار آسان است، اما درك بخشهای آن،بنابراين رمز بزرگتر از چیزی است که ما ميخواهیم
idiff )f1 , f2 , fin , fout( / * process diffs * /
FILE * f1 , * f2 , * fin , * fout ;
}
char * temfile = ″ idiff – x x x x x x ″ ;
char buf ] BUFSIZ[ , buf2 ] BUFSIZ[ , * mktemp ) ( ;
FILE * ft , * efopen ) ( ;
int cmd , n , from1 , to 1 , from 2 , to 2 , nf1 , nf2 ;
mktemp )tempfile( ;
nf1 = nf2 = 0 ;
while )fgets )buf , size of buf , fin( ! = NULL( }
parse )buf , $ from1 , $ from 1, $ to 1 , $ cmd , $ from 2 , $ to 2(;
n = tol – from1 + to2 – from 2 + 1 ; /* # lies from diff * /
if )cmd = = ′ c ′(
n+=2;
else if )cmd = = ′ a ′ (
from 1 + + ;
else if )cmd = = ′ d ′(
from 2 + + ;
printf ) ″ % s ″ , buf( ;
while )n - - > 0( }
fgets )buf , size of buf , fin( ;
210/322 محیط برنامه سازی لینوکس
print f ) ″ % s ″ , buf ( ;
{
do }
print f ) ″ ? ″( ;
fflush )stdout( ;
fgets )buf , sizeof buf , stdin( ;
switch )buf ]0[ ( {
case ′ > ′ :
nskip )f1 , to 1 – nf1( ;
n copy )f2 , to2 – nf2 , fout( ;
break ;
case ′ < ′ :
nskip )f2 , to2 – nf2 ( ;
n copy )f1 ,to1 – nf1 , fout( ;
break ;
case ′ e ′ :
ncopy )f1 , from 1 – 1 – nf1 , fout( ;
nskip )f2 , from 2 – 1 – nf2( ;
ft = efopen )tempfile , ″ w ″( ;
ncopy )f1 , tol + 1 – from1 , ft( ;
fprintf )ft , ″ - - \ n ″( ;
ncopy )f2 , to 2 + 1 – from 2 , ft (;
fclose )ft ( ;
sprint f )buf2 , ″ ed % s ″ , temp file(;
system )buf2( ;
ft = efopen )tempfile , ″ ed % s ″ , temp file( ;
system )buf2( ;
ft = efopen )tempfile , ″ r ″( ;
ncopy )ft , MUGE , fout( ;
fclose )ft(;
break ;
case ′ ! ′ :
system )buf + 1( ;
printf ) ″ ! \ n ″( ;
break ;
default :
print f ) ″ < or > ore or ! \ n ″( ;
break ;
{
{ while )buf ]0[ ! = ′ < ′ $ $ buf ]0[ = ′ > ′ $ $ buf ]0[ ! = ′ e ′(;
nf 1 = to 1 ;
nf 2 = to 2 ;
{
ncopy )f1 , HUGE , fout ( ; / * can fail on very long files * /
unlike )tempfile( ;
211/322 محیط برنامه سازی لینوکس
{
چهار شماره سطر و فرمان را استخراج، انجام ميشودdiff فرمان را انجام ميدهد اما کار دشوار تجزيه سطرها که توسط، parse تابع
. )d ياa ، b ، c ميکند (يکي از
. ميتواند يك يا دو شماره سطر را در هر طرف از طرف فرمان بوجود آورد،diff اندکي پیچیده است چون، parse
parse )s , pfrom 1, pto 1 , pcmd , prom 2 , pto2(
char * s ;
int * pcmd , * pfrom1 , * pto1 , * pfrom2 , * pto2 ;
}
# define a2i )p( while )is digit )*s( ( p = 10 * )p1 + * s + + - ′o′
* prom1 = * ptol = * pfrom 2 = * pto 2 = o ;
a2i ) * pfrom1 (;
if )* s = = ′ , ′ ( }
s++;
a2i )* pto1( ;
{ else
* pto 1 = * pfrom 1 ;
* pcmd = * s + + ;
a2i ) * pfrom 2( ;
if )* s = = ′ , ′ ( }
s++
a2i ) * pto2( ;
{ else
* pto 2 = * pfrom 2 ;
{
. انجام ميدهد، به عدد صحیح را در چهار مکاني که رخ ميدهدAscll تبديل ويژه ما از، a2i درشت دستورالعمل
: از تعداد خاصي از سطرهای يك فايل عبور ميکنند و يا آنها را کپي ميکنند، ncopy وnskip
nskip )fin , n ( / * skip n lines of file fin * /
FILE * fin ;
}
char buf ]BUFSIZ[ ;
while )n - - > 0(
fgets )buf , sizeof buf , fin( ;
{
n copy )fin , n , fout( / * copy n lines from fin to fout * /
FILE * fin , * fout
}
char buf ]BUFSIZ[ ;
while ) n - - > 0( }
if )fgets )buf , sizeop buf , fin( = = null(
return ;
fputs )buf , fout( ;
{
{
212/322 محیط برنامه سازی لینوکس
همانطور که نشان ميدهد ، idiff ،نميتواند با مليمت از سیستم خارج شود ،اگر دچار وقفه شود ،چون ،idiffفايلهای متعددی را که
در tmp/قرار دارند ،رها ميکند .در فصل بعد ،ما نشان ميدهیم که چگونه برای حذف فايلهای موقتي ،مانند فايلهايي که در اينجا
استفاده ميشوند ،از وقفهها استفاده کنیم.
مشاهدة دشوار در zapو ، idiffاين است که قسمت اعظم کار سخت ،توسط فردی ديگر انجام شده است .اين برنامهها ،صرفا ً يك
واسطة مناسب را روی برنامهای ديگر قرار ميدهند که اطلعات درست را محاسبه ميکند .به دنبال فرصتي بودن برای ساخت بر روی
کار فردی ديگر ،ارزشمندتر اين است که خودتان آن را انجام دهید ـ اين يك روش ارزان قیمت و سودمندتر است.
تمرين 13ـ 6ـ يك فرمان qرا به idiffاضافه کنید :پاسخ ،> qهمه باقیمانده انتخابهای ‘ > ’را به طور خودکار ميگیرد؛ < qهمه
باقیماندة انتخابهای ‘ < ’ را ميگیرد.
تمرين 14ـ 6ـ idiffرا بهگونهای تغییر دهیدکه همه آرگومانهای diffاز diffعبورکنند؛ – bو ، h-احتمالً منتخبها هستند Idiff .را
به گونهای تغییر هید که يك ويراستار متفاوت بتواند شناسايي شود ،مانند
$ idiff – eanother – editor file 1 file 2
چگونه اين دو تغییر برهم کنش دارند؟
تمرين 15ـ 6ـ برای استفاده از popenو pcloseبه جا ی يك فايل موقتي برای خروجي diff ، idiffرا تغییر دهید .چه تفاوتي در
سرعت و پیچیدگي برنامه بوجود ميآيد؟
تمرين 16ـ 6ـ diffدارای اين ويژگي ميباشد که اگر يکي از آرگومانهای آن ،يك فهرست راهنما باشد ،به جستجوی آن فهرست
برای يك فايل با نامي شبیه آرگوماني ديگر ميپردازد .اما اگر شما همین کار را با idiffانجام دهید ،به شکلي عجیب خراب ميشود.
شرح دهید چه اتفاقي ميافتد و سپس آن را ثابت کنید.
9ت 6 ت دستيابي به محيط
دستیابي به متغیرهای محیط شل از يك برنامه cآسا است و چنین چیزی گاهي اوقات مي تواند برای ساختن برنامههايي موافق با
محیطشان و بدون نیاز به کاربرهای آنها ،استفاده شود .برای مثال ،فرض کنید که شما از يك پايانه استفاده ميکنید که در آن اندازه پرده
نمايش بزرگتر از 24سطر نرمال ميباشد .اگر شما بخواهید از pاستفاده کنید و ازتواناييهای پايانه خود حداکثر استفاده را ببريد ،چه
انتخابهايي برای شما وجود دارد؟ مشخص کردن اندازه پرده نمايش در هر زماني که شما از pاستفاده ميکنید ،دشوار است :
… $ p – 36
:خود قرار دهید binشما بايد همیشه يك نام شل را در
$ cat / usr / you / bin / p
* exec / usr / bin / p – 36 $
$
سومین راه حل ،تغییر Pبرای استفاده از يك متغیر محیط ميباشد که ويژگیهای پايانة شما را تعريف ميکند .فرض کنید که شما متغیر
213/322 محیط برنامه سازی لینوکس
تمرين 17ـ 6ـ idiffرا به گونهای تغییر دهید که به جستجوی محیط برای نام ويراستاری بپردازد که استفاده ميشود .برای استفاده از
PAGESIZE ، 2و ، 3غیره را تغییر دهید.
تاريخچه و نكات كتابشناسي
کتابخانه استاندارد ، I/Oپس از کتابخانه قابل انتقال از میك لسك ،توسط دنیس ريتچای ،طراحي شد .هدف هر دو بسته نرم افزاری،
فراهم کردن روشهای ساده استانداردی است که برنامهها بتوانند توسط آنها ،بدون تغییر از سیستمهای يونیکس به سیستمهای
غیريونیکس حرکت کنند.
و تکنیکي بل لبز ،1976 ،توصیف ميشود .به نقل قول از میکلوری « من حداقل سه آلگوريتم کامل متفاوت را قبل از آلگوريتم نهايي
بررسي کردهام diff .يك مورد ناب و اصیل نه فقط برای تعیین صلحیت ـ محض در يك برنامه ميباشد ،بلکه همچنین آن را مجدداً
بررسي میکنید تا جايي که صحیح باشد».
215/322 محیط برنامه سازی لینوکس
همه ورودی و خروجي از طريق خواندن و نوشتن فايلها انجام مي شود ،چون همه طرحها پیراموني ،حق پايانه شما ،فايلهايي در
سیستم فايل مي باشند .مفهوم اين عبارت اين است که يك اتصال منفرد همه ارتباط بین يك برنامه و طرحهای پیراموني را انجام مي
دهد .
در عمومي ترين مورد ،قبل از خواندن يا نوشتن يك فايل ،لزم است که سیستم خود را برای انجام آن ،مطلع سازيد ،فرآيندی که
بازکردن فايل نامیده مي شود .اگر شما قصد نوشتن بر روی يك فايل را داريد .بوجود آوردن آن فايل نیز مي تواند لزم باشد .سیستم
صحت انجام کار شما را کنترل مي کند (آيا فايل خارج مي شود ؟ آيا شما مجاز به دستیابي به آن هستید ؟) و اگر همه چیز درست
باشد .يك عدد صحیح مثبت را که توصیف گر فايل نامیده مي شود ،باز مي گرداند .هر موقع که I/Oبر روی فايل انجام شود ،
توصیف گر فايل برای شناسايي فايل ،به جای اسم استفاده مي شود .همه اطلعات در مورد يك فايل باز .توسط سیستم حفظ مي
216/322 محیط برنامه سازی لینوکس
شود و برنامه شما ،فقط توسط يك توصیف گر فايل ،به فايل رجوع مي کند .يك اشاره گر FILEبه همان صورتي که در فصل 6
توصیف شد .به ساختاری اشاره مي کند که در میان ساير چیزها دارای توصیف گر شد .به ساختاری اشاره مي کند که در میان ساير
چیزها ،دارای توصیف گر فايل مي باشد ، fileno)ff( macro .که در > <stdio.bتعريف مي شود .توصیف گر فايل را باز مي
گرداند .
آرايش های خاصي برای مناسب ساختن ورودی وخروجي پايانه وجود دارند .زماني که يك برنامه توسط شل شروع مي شود ،سه
فايل باز را با توصیف گران فايل 0,1و 2بدست آورد که ورودی استاندارد ،خروجي استاندارد و خطای استاندارد نامیده مي شوند .
هر سه مورد ،توسط پیش فرض به پايانه متصل مي شود بنابراين اگر يك برنامه فقط توصیف گر فايل 0را بخواند و توصیف گران فايل
1و 2را بخواند ،مي تواند 1/0را بدون باز کردن فايلها بخواند .اگر برنامه فايلهای ديگر را باز کند ،آنها دارای توصیف گران فايل 3و
4و غیره خواهند بود .
اگر 1/0به سمت فايلها يا لوله ها تغییر جهت دهد و يا از آنها خارج شود ،شل ،تخصیص های پیش فرض را برای توصیف گران
فايل 0و 1از پايانه به سمت فايلهای نام گذاری شده تغییر مي دهد .در حالت عادی ،توصیف گر فايل ، 2متصل به پايانه باقي مي
ماند ،در نتیجه پیامهای خطا مي توانند به آنها بروند .عملکردهای شل ،مانند< filename 2و ، 2 &1منجر به آرايشهای پیش فرضها
مي شوند ،اما تخصیص های فايل توسط شل تغییر مي کنند و نه توسط برنامه ( .برنامه خودش مي تواند اين تخصیص ها را مجددا
مرتب کند ،اگر بخواهیم ،اما اين مورد نادر است .
تمام ورودی و خروجي توسط دوفراخواني سیستم انجام مي شود write , read ،که از cتوسط عملیات هايي با همین نام ،دستیابي
مي شوند .برای هر دو ،اولین آرگومان ،توصیف گر فايل است .دومین آرگرمان ،يك آرايه از بايتهايي مي باشد که به عنوان منبع يا
مقصد داده ها ارائه مي شود .سومین آرکومان ،تعداد بايتهايي است که بايد منتقل شوند .
;Int fd,n,nread , written
;[Char buf ]SIZE
;(Nread = read )fd,buf,n
;(Nwritten=write )fd , buf,n
هر فراخواني ،يك شما را از تعداد بايتهای انتقال يافته را باز مي گرداند .در خواندن ،تعداد بايتهای بازگردانده شد ،ممکن است کمتر
از تعداد بايتهای درخواست شده باشد ،چون ،کمتر از nبايت برای خواندن باقي مي ماند ( .زماني که فايل يك پايانه است red ،در
حالت عادی ،فقط تا سطر بعدی را مي خواند که معمول کمتر از چیزی است که درخواست مي شود ).ارزش بازگشت صفر ،در انتهای
فايل ايجاب مي کند و ،-1يك خطا را نشان مي دهد .برای نوشتن ،ارزش بازگردانده شده ،تعداد بايتهايي است که حقیقتا نوشته مي
شوند و يك خطا رخ مي دهد اگر اين تعداد ،برابر با تعداد بايتهای در نظر گرفته شده برای نوشتن نباشند .
زماني که تعداد بايتهايي که بايد خوانده يا نوشته شوند ،محدود نمي شود ،عمومي ترين ارزشها ،1که به معنای يك کاراکتر در يك زمان
مي باشد(میانگیر نشده ) و اندازه يك بلوك بر روی يك ديسك که اغلب دارای 512يا 1024بايت مي باشد ( ،پارامتر BUFSIZدر
> <stdio .bدارای اين ارزش مي باشد ) هستند .
برای شرح ،در اينجا برنامه ای وجود دارد که ورودی خود را برای خروجي خود کپي مي کند .چون ،ورودی و خروجي مي توانند
217/322 محیط برنامه سازی لینوکس
برای هر فايل يا طرحي مجددا تغییر جهت دهند ،اين برنامه ،حقیقتا هر چیزی را برای چیزی کپي مي کند و اين برنامه يك تحقق
چارچوب اصلي catمي باشد
/*cat:minimal version*/
#define SIZE 512/*arbitrary*/
main]1
.
[char buf]SIZE
;int n
while ))n=read )0,buf , size of buf((>0
;(write )1,buf,n
; (exit )0
اگر اندازه فايل ،يك مضرب از SIZEنباشد ،برخي از ، readتعداد کمتری از بايتهايي را که بايد توسط writeنوشته شوند ،باز مي
گرداند و فراخواني بعدی برای readکه پس از آن ،صفر بر مي گردد .
خواندن ونوشتن در قطعاتي که ديسك را تطبیق مي کنند ،بسیار موثر مي باشد ،اما حتي I/Oبه صورت يك کاراکتر در يك زمان ،
برای میزان ناچیزی از مقادير داده ها ،امکان پذير است .چون کرنل ،داده های شما را میانگیر مي کند و ارزش اصلي ،فراخواني های
سیستم مي باشد .برای مثال edاز خواندن های يك بايتي برای بازيابي ورودی استاندارد آن ،استفاده مي کند .ما اين نسخه از catرا
روی يك فايل با 54000بايت زمان داديم ،برای 6ارزش از : SIZE
(Tim )user + system, sec
SIZE Pdp= 11.70 Vax-11.750
1 0/271 8/188
10 9/29 3/19
100 8/3 6/2
512 3/1 0/1
1024 2/1 6/0
5120 0/1 6/0
اندازه بلوك ديسك 512 ،بايت بر روی سیستم PDP-11و 1024بايت بر روی VAXمي باشد .تقريبا برای فرآيندهای متعدد مجاز
مي باشد که در يك زمان به يك فايل دست يابند و حقیقتا ،يك فرآيند مي تواند نوشته شود ،زماني که فرآيندی ديگر خوانده مي شود
اگر اين چیزی نباشد که شما مي خواهدی مي توان نگران کننده باشد ،اما گاهي اوقات مفید است .اگر چه ،يك فراخواني برای read
،صفر را باز مي گرداند و در نتیجه علمت های انتهای فايل را باز مي گرداند ،اما اگر داده های بیشتری بر روی آن فايل نوشته شود ،
readبعدی ،بايتهای بیشتری را در دسترس مي يابد .اين مشاهده ،مبنای برنامه ای است که redslowنامیده مي شود برنامه ای که
خواندن ورودی خود را ،بدون توجه به اين که آيا به انتهای فايل مي رسد يا نه ،ادامه مي دهد readslow.برای تماشای پیشرفت يك
برنامه مناسب است .
#slowprog > tem
5213 process - id
# redslow <tem: grep sometting
به عبارت دير کي برنامه کند که خروجي را در يك فايل تولید مي کند ؛ readslowو شايد در همکاری با برنامه ای ديگر ،انباشته
218/322 محیط برنامه سازی لینوکس
غیر از فايلهای پیش فرض ورودی ،خروجي و خطای استاندارد ،شما بايد آشکارا ،فايلها را به منظور خواندن يا نوشتن آنها بازکنید .دو
فراخواني سیستم برای اين کار وجود دارند . creat , open ،
Openتا حدودی شبیه به fopenدر فصل قبل مي باشد ،به استثنای اينکه به جای بازگرداندن يك اشاره گر فايل ،يك توصیف گر
فايل را بر مي گرداند که يك intمي باشد .
; Char*name
;Int fd , rwmode
;(Fd=open )name , rwmode
همانند ، fopenآرگومان ، nameيك رشته کاراکتر و شامل نام فايل مي باشد .اما دستیابي به آرگومان modeمتفاوت است rw :
modeبرای خواندن صفر ،برای نوشتن 1و برای بازکردن يك فايل چه برای خواندن و چه براينوشتن 2مي باشد open ، 1- .را باز
مي گرداند ،اگر خطايي رخ دهد و درغیر اين صورت يك توصیف گر بهتر فايل را باز مي گرداند .
تلش برای بازکردن فايلي که وجود ندارد يك خطاست .فراخواني سیستم ، creatبرای ايجاد فايلهای جديد و يا خواندن مجدد
219/322 محیط برنامه سازی لینوکس
فراخواني های سیستم مورد بحث واقع شده در اين بخش ،و در حقیقت همه فراخوانیهای سیستم مي توانند منجر به خطا شوند .
معمول آنها ،يك خطا را با برگرداندن يك ارزش -1نشان مي دهند .گاهي اوقات فهمیدن اينکه چه خطای ويژه ای رخ داده است .
خوب است برای اين منظور همه فراخوانیهای سیستم ،زماني که مناسب است يك عددخطا را در يك عدد صحیح خارجي جا مي
(معني اعداد متعدد خطا ،در مقدمه بخش 2از کتاب راهنمای برنامه نويس يونیکس ،فهرست وار بیان مي شود ) با استفاده از error
برنامه شما برای مثال مي تواند ،تعیین کند که آيا تلش برای بازکردن يك فايل با شکست مواجه شده است ،به خاطر اينکه فايل
وجود نداشته است و يا به خاطر اينکه شما مجاز به خواندن آن نبوده ايد .
همچنین يك آرايه از رشته های کاراکتر sys-errlistوجود دارد که توسط errorمشخص مي شود و اعداد را به يك رشته معني دار
ترجمه مي کند .نسخه errorما ،از اين ساختار داده ها استفاده مي کند :
&
I/Oفايل در حالت عادی تربیتي است :هر خواندن يا نوشتن در داخل فايل درست سپس از مورد قبلي رخ مي دهد .اما زماني که لزم
است ،يك فايل مي تواند در يك ترتیب قراردادی خوانده يا نوشته شود .فراخواني سیستم ، lseekراهي را برای وارد شدن در يك
فايل بودن خواندن يا نوشتن واقعي فراهم مي کند .
; Int fd , origin
;()Long offset , pos, lseek
;(Pos=lseek )fd , offset , origin
موقعیت فعلي در فايل را که توصیف گر آن fdمي باشد مجبور به حرکت به سمت موقعیت offsetمي کند ،که متناسب با موقعیت
مشخص شده توسط originمي باشد .خواندن يا نوشتن بعدی در آن موقعیت شروع مي شود origin .مي تواند 0 ،و 1يا 2باشد
برای اينکه مشخص کند offsetاز آغاز ،از موقعیت قطعي جديد يا -1برای يك خطا مي باشد .برای مثال برای فیحصه کردن به يك
فايل ،قبل از نوشتن در جسجوی انتهای فايل باشید :
;(Lseek )fd , ol,2
برای بازگشتن به آغاز (باز پیچش) و
; (Lseek )fd , ol ,0
برای تعیین موقعیت فعلي :
;(Pos = lseek )fd,ol,1
توجه داشته باشید به آرگومانـ offset : olبه يك عدد صحیح طولني مي باشد 1( .درـ lseekبه منظور تشخیص آن از ششمین
ويرايش سیستم فراخواني seekمي باشد که از اعداد صحیح کوچك استفاده مي کند ).
با : seekو اين امکان وجود دارد که با فايلها کم و بیش شبیه آرايه های بزرگ به قیمت دستیابي کندتر ،برخورد کنیم .برای مثال ،تابع
زير هر عدد از بايتها را از سرمکاني در يك فايل مي خواند .
Get )fd , pos , buf , n(/*read n bytes from position pos*/
;Int fd,n
Long pos
;Char*buf
If )lseek)fd ,pos,0(=-1( /*yet to pos*/
;Return -1
Else
;(Return read )fd,buf ,n
{
تمرين . 7-3برای استفاده از يك آرگومان فايل اگر وجود دارد readslow ،را تغییر دهید انتخاب – eرا اضافه کنید :
& readslowe
منجر مي شود که readslowدر جستجوی انتهای ورودی قبل از شروع به خواندن باشد lseek .بر روی يك لوله چه کاری انجام مي
دهد ؟
222/322 محیط برنامه سازی لینوکس
موضوع بعدی ،چگونگي حرکت از طريق سلسله مراتب فهرست راهنما مي باشد .برای چنین چیزی در حقیقت از فراخوانیهای جديد
سیستم استفاده نمي شود ،فقط برخي از فراخوانیهای قبلي در يك متن جديد قرار مي گیرند .ما با نوشتن يك تابع باعنوان spname
شرح مي دهیم که چگونه بر اسامي فايلهای دارای تلفظ غلط غلبه کنیم .تابع
;(N=spname )name ,new nume
به جستجوی يك فايل بايك نامـ « به میزان کافي نزديكـ » به منظور نامگذاری آن مي پرداز د .اگر يك فايل يافت شودـ .درون
newnameکپي مي شود .ارزش nبازگردانده شده توسط spname ، 1-مي باشد اگر هیچ فايلي که به میزان کافي نزديك باشد ،
يافت نشود .ارزش n 0مي باشد اگر يك تطبیق واقعي وجود داشته باشد و 1است اگر يك تصحیح ساخته شود .
Spnameيك افزايش مناسب به فرمان Pمي باشد .اگر شما سعي کنید که يك فايل را تايپ کنید اما اسم آن (غلط تلفظ کنید p ،مي
تواند از شما سئوال کند اگر شما واقعا منظورتان چیز ديگری است :
&p/urs/.YX/comd/p/spnam.cاسم به مدار وحشتناك نادرست بیان شده
/usy/syc/cmd/p/spname.c:yتصحیح مورد قبول بیان شده
/*spname: return correctly spelled filename*/
همانگونه که ما نوشتیم spname ،در هر جزء از اسم فايل ،سعي مي کند اشتباهاتي را که در آنها يك حرف تنها افتاده است يا اضافه
شده است يا تنها يك حرف غلط است و يا يك جفت از حروف با هم جابجا شده اند تصحیح کند و همه اين موارد در فرمان بال شرح
داده مي شوند .اين يك لطف برای تايپیست های شلخته است .
قبل از نوشتن رمز ،يك بررسي کوتاه از ساختار سیستم فايل ،اشکالي ندارد .يك فهرست راهنما ،فايلي است که شامل يك فهرست از
اسامي فايلها و يك نشانه از جايي است که آنها قرار دارند «مکان » حقیقتا يك شاخص در جدولي ديگر مي باشد که جدول inodeنام
دارد inocle .برای يك فايل جايي است که همه اطلعات در خصوص فايل به جز اسم آن ،حفظ مي شود .يك مدخل فهرست
راهنما ،متشکل از فقط دو مورد مي باشد .يك عدد inodeو يك اسم فايل .تشخیص دقیق را مي توان در فايل > <sys>dir.hپیدا
کرد :
& cat/usr/include / sys/dir.h
#define DIRIZ 14 /*max length of file name*/
struct direct /*structure of directory entry */
}
ino-td- ino; /*inode number */
char d-name ]DIRSIZ[ ; /*file name */
;{
&
تايپ ino-tيك typedefمي باشد که شاخص را درون جدول inodeتوصیف مي کند ، ino-t .به صورت يك shortبدون علمت
بر روی نسخه های PDP-11و VAXاز سیستم مي باشد ،اما چنین چیزی قطعا گونه ای از اطلعات واقع شده در يك برنامه نمي
باشد :بلکه بر روی يك ماشین متفاوت ،متفاوت مي باشد .از اين رو ، typedef ،يك مجموعه کامل از تايپ های سیستم در >
223/322 محیط برنامه سازی لینوکس
int d , nd , fd;
struct}
ino-tino ;
char name ]DIRSIZ+1[ ;/*1 more than in dir.b*/
{nbuf ;
nbuf . name ]DIRSIZ[=IO ;/*+1 for terminal io */
if )dir ]0[ == 0( /*current directory */
dir =0;
d=3; /*minimum distance*/
if ))fd = open)dir , 0(( == -1(
return di
while )read )fd,)char *(&nbuf , sizeof)structdirect((>0(
if)nbuf.ino(}
nd = spdist )nbuf name,guess(;
if)nd<=d&nd !=3(}
strcpy)best , nbuf . name(;
d=nd;
if )d==0( /*exct match*/
break ;
{
{
close )fd( ;
returnd ;
{
يك ورودی فهرست راهنما را در هر زمانmindist جستجو مي شود0 ، خالي باشدmindist اگر نام فهرست راهنمای ارائه شده برای
برای محاسبه تعدادsizeof يك ساختار مي باشد نه يك آرايه از کاراکترها ما ازread توجه داشته باشید که میانگیر برای. مي خواند
. استفاده مي کنیم، بايتها و حرکت آدرس به سمت يك اشاره گر کاراکتر
صفرcnode اخیرا مورد استفاده نباشد (چون يك فايل حذف شده است ) در نتیجه مدخل، اگر يك شکاف دريك فهرست راهنما
تست فاصله عبارت است از. است و از اين موقعیت به صورت جهشي عبور مي شود
If )nd <=d...(
به جای
if )nd <d...(
. مي باشد که همیشه اولین ورودی در يك فهرست راهنما است0 هر کاراکتر مفرد ديگری يك تطبیق بهتر از، بنابراين
/*spdist : return distabce between two names*/
/*
*very rough spelling metric:
*o if the string are identical
* 1 if the string are identical
*2 if one char wrong,added or deleted
*3 otherwise
*/
# define E& )s,t()strcmp )s,t(==0(
spdist )s,t(
char*s,*t;
225/322 محیط برنامه سازی لینوکس
}
while )*s++==*t(
if )*t++== io(
return o ; /*exact matoh */
if )*--s(}
if )*t(}
if )s)1[&&t ]1[&&*s == t ]1[
&&*t == s]1[&&E* )S+2 , t+2((
return 1; /*transposition */
if )Ea )s+1 , t+1(
return2 ; /*1 char mismatch */
{
if )Ea)s+1, t((
return2; / *extra character */
{
if )*t&& E&)S,t+1((
return 2; /*missing character */
return 2 ;
{
: آسان استp ادغام تصحیح تلفظ در، را داريمspname زماني که ما
/*p:print input in chunks )version 4 (*/
# include cstdio.bs
# define PAEGSIZE 22
char *progname ; /*programname for error message */
main )argc , argv(
int argc ;
char*argv ] [ ;
}
FILE *FP,*efopen ) ( ;
Int ; pagesize= PAGESIZE ;
Char *p,get v ) ( , buf ]BUFSIZ[;
Programe = argv]0[ ;
If ))p=getenv )PAGESIZE(( !=NULL(
Pagesize = atoi)p(;
If )argc>1&&argv ]1[ ] 0[ == - }
Pugesize = atoi)&argv ] 1[ ]0[ (;
Argc --;
Argv ++;
{
if )argc==1(
print )stdin ,pagesize(;
else
for )I=1 , I<argc;I ++(
switch )spname )argv ]I[ ( , buf((}
case -1 ; /*nomatchpossible */
fp = efopen cargv ]I[ , r(;
break;
226/322 محیط برنامه سازی لینوکس
در اين بخش به ما بحث در خصوص فراخوانیهايي از سیستم مي پردازيم که به سیستم فايل و بويژه با اطلعاتي در خصوص فايلها ،
مانند اندازه ،تاريخ ها ،اجازه ها و مواردی از قبیل مي پردازند .اين فراخوانیهای سیستم به شما اين امکان را مي دهند که همه
اطلعاتي را بدست آوريد که ما در خصوص آنها در فصل 2صحبت کرديم .
مي خواهیم وارد خود inodesشويم .بخشي از inodeتوسط يك ساختار با عنوان statتوصیف مي شود که در ><sys /stat .b
تعريف مي شود :
227/322 محیط برنامه سازی لینوکس
ما بعدا قصد داريم برنامه ای را با عنوان SVبنويسیم که شبیه CPمي باشد و يك مجموعه از فايلها را برای يك فهرست راهنما کپي
مي کند ،اما هر فايل مقصد را فقط زماني تغییر مي دهد که فايل وجود ندارد و يا قديمي تر از مبدا مي باشد SV .برای ذخیره کردن
مي باشد .ايده دراينجا اين است که SVچیزی را که بیشتر جديد به نظر مي رسد ،روی هم کپي نمي کند SV .اکثر اطلعات را در
inodeبه جای checkmailاستفاده مي کند .طرحي که ما برای svاستفاده مي کنیم عبارت است از :
& sv file 1 file 2... dir
فايل 1را برای dir/file1و فايل 2را برای dir/file 2و غیره کپي مي کند ،به استثنای زماني که يك فايل مقصد ،جديدتر از فايل
مبدا آن مي باشد ،هیچ گونه کپي انجام نمي شود و يك اخطار پرينت مي شود .برای اجتناب از ايجاد کپي های متعدد از فايلهای
مرتبط sv ،در هیچ کدام از اسامي فايلهای مبدا به s/اجازه نمي دهد .
/*sv: save new files */
># include <stdio .h
># include <sys/types.h
># include <sys/stat .h
># include <sys/stat .h
; char*programe
(main)argc,argv
230/322 محیط برنامه سازی لینوکس
int argc;
char *argv ] [ ;
}
int I ;
struct stat stbuf ;
char *dir = argv ]argc-1[
progname = argv ]0[ ;
if )argv<=2(
error )usage :%s files ...dir , progname(;
if )stat )dir,&stbuf(== -1
error )cant access directory % s, dir(;
if ))st buf.st-mode &s-ifmt(! =s-ifdir(
error )%s is not a directory , dirl;
for )I=1,I<argc-1 , I ++(
sv)argv ]I[ , dir( ;
exit )0( ;
{
زمانهای موجود درinode 0:00( از مدتها قبل برحسب ثانیه مي باشندGMT بنابراين فايلهای قديمي تر، )1970 ، اول ژانويه
دارای ارزشهای کمتری در زمینهst-mtime خود مي باشند.
SV)file , dir( /*save file in dir*/
Char *file , * dir
}
struct stat sti , sto ;
int fin , fout , n;
char target ]BUFSIZE[ , buf ]BUFSIZ[, *index2
sprint f )target , %s/%s , dir , file( ;
if )index )file , /(! =Null(/*strchrcin some systems */
error )wont handle/s in %s , file(;
if )stat )file, &sti (=-1
error)can't stat %s , file( ;
if )stat)target , &sto (==-1( /*target not present*/
stoost - mtime =0 ; /* somake it look old */
if )sti.st-mtime< sto .st-mtime( /*target is newer */
fprint f )stderr , % s : % s not copied\n ,
progname ,file ( ;
else if ))fin=open )file ,0( == -1 (
error )can't open file % s , file (;
else if ))fout = creat )target , stist - mode(( == -1
error )can't create % s , target(;
else
while ))n=read)fin , buf , sizeof buf ((>0(
if )write )fout , buf , n (!= n(
error )error writing % s , target(;
close )fin( ;
close )fout ( ;
{
231/322 محیط برنامه سازی لینوکس
ما به جای تابعهای استاندارد I/Oاز creatاستفاده کرديم ،در نتیجه svمي تواند از وضعیت فايل ورودی محافظت کند ( .توجه
داشته باشید که strchr , indexنامهای متفاوت برای يك زير برنامه مي باشند و کتاب راهنمای خود را تحت )string )3کنترل کنید
برای اينکه ببنید سیستم شما از چه نامي استفاده مي کند ) .
اگر چه برنامه ، svتا حدودی مشخص مي باشد ،اما برخي از عقايد مهم را نشان مي دهد .بسیاری از برنامه ها « ،برنامه سیستم »
نمي باشند ،اما مي توانند از اطلعات ذکر شد ه توسط سیستم عامل استفاده کنند و به فراخواني های سیستم دست يابند .برای چنین
برنامه هايي لزم است که ارائه اطلعات ،فقط از فايلهای عنوان استاندارد مانند > <dir . bو > ، <stat.hظاهر شود و اين برنامه ها
شامل آن فايلها مي باشند ،به جای اينکه اعلن های واقعي را در خودشان قرار دهند .چنین رمزی ،به احتمال قوی ،قابل انتقال از يك
سیستم به سیستمي ديگر مي باشد .
همچنین ارزشمند است که حداقل در سوم رمز در ، svکنترل خطا باشد .در مراحل اولیه نوشتن يك برنامه ،صرفه جويي در استفاده
از خطا ،وسوسه انگیز مي باشد ،چون يك انحراف از وظیفه اصلي مي باشد .و زماني که برنامه کار مي کند ،اشتیاق در مورد برگشتن
برای انتخاب بازبیني هايي که يك برنامه کار مي کند ،اشتیاق درمورد برگشتن برای انتخاب بازبیني هايي که يك برنامه خصوصي را به
برنامه ای تبديل مي کنند که بدون توجه به اين که چه اتفاقي مي افتدکار مي کند ،دشوار است .
، Svيك شاهد در مقابل همه اشتباهات ممکن نمي باشد – svدر زمانهای نامناسب به وقفه های نمي پردازد – اما دقیق تر از اکثر
برنامه ها مي باشد .برای تمرکز بر روی فقط يك نکته در يك لحظه ،بیان writeنهايي را در نظر بگیريد .خراب شدن writeبه
ندرت رخ مي دهد .بنابراين اکثر برنامه ها اين احتمال را ناديده مي گیرند .اما ديسکها از فضا خارج مي شوند و کاربرها ،پافراتر از
نقل قولها مي گذارند ؛ خطوط ارتباطات شکسته مي شود .همه اين موارد مي توانند منجر به خطاهای writeشوند و شما بهتر عمل
خواهید کرد اگر در خصوص آنها مطالبي بشنويد به جای اينکه برنامه به آرامي وانمودند که همه چیز خوب است .
درست اين است که کنترل خطا خسته کننده اما مهم است .ما در اکثر برنامه های اين کتاب به خاطر محدوديتهای مکاني و تاکید بر
موضوعات جالب تر سرفراز بوده ايم .اما ،برای تولید واقعي برنامه ها ،شما نمي توانید خطاها را ناديده بگیريد .
تمرين . 7-10برای تشخیص فرستنده پست ،به عنوان بخشي از پیام «شما نامه پستي داريد » chekemailرا تغییر دهید .نکته
lseek-ss canf
تمرين chekmail . 7-11را به گونه ای تغییر دهید که قبل از اينکه وارد حلقه خود شود ،برای فهرست پستي تغییری نکند .آيا اين
کار دارای اثر قابل اندازه گیری بر عملکرد خود مي باشد ؟ (سخت تر) ،آيا شما مي توانید يك نسخه از checkmailرا به گونه ای
بنويسید که فقط نیاز به يك فرآيند برای اطلع به همه کاربرها باشد؟
تمرين . 7-12يك برنامه watchfileبه گونه ای بنويسید که يك فايل را بررسي کند و فايل را از آغاز هر زماني که تغییر مي کند ،
پرينت کند .چه موقع شمامي توانید از آن استفاده کنید ؟
تمرين sv . 7-13در استفاده از خطای خود ،تقريبا سختگیر مي باشد .آن را به گونه ای تغییر دهید که ادامه يابد ،اگر نمي تواند فايلي
را پردازش کند .
تمرين sv . 7-14را بازگشتي بسازيد :اگر يکي از فايلهای مبدا ،يك فهرست راهنما باشد ،آن فهرست و فايل هايش به يك روش
پردازش مي شوند cp .را بازگشتي بسازيد .بحث کنید که آيا sv,cpبايد يك نوع برنامه باشند ،در نتیجه cp-vکپي را انجام نمي
دهد ،اگر فايل مقصد جديدتر باشد .
تمرين . 7-15برنامه randomرا بنويسید :
232/322 محیط برنامه سازی لینوکس
47فرآيندها
اين بخش ،توصیف مي کند که چگونه يك برنامه را از داخل برنامه ای ديگر ،اجرا کنیم .آسانترين راه برای انجام آن ،با زير برنامه
کتابخانه استاندارد ، system .مي باشد .که در فصل 6ذکر شد اما سانسور شد system .يك آرگومان را مي گیرد ،يك سطر فرمان
دقیقا به همان صورتي که در پايانه تايپ مي شود (به جز برای سطر جديد در انتها ) و آن را در يك زير شل ،اجرا مي کند .اگر سطر
فرمان بايد از قطعات ساخته شود ،توانايي های فرمت درون حافظه sprintfمي تواند مفید باشد .در پايان اين بخش ،ما يك نسخه
ايمن تر از systemرا برای استفاده توسط برنامه های برهم کنش نشان مي دهیم ،اما در ابتدا ما بايد قطعات را از چیزی که ساخته مي
شود بررسي کنیم .
مهمترين عملکرد ،اجرای برنامه ای ديگر بدون بازگشت و با استفاده از فراخواني سیستم execlfمي باشد .برای مثال .برای پرينت
تاريخ به عنوان آخرين اقدام يك برنامه اجرا از برنامه زير استفاده کنید :
; )Execlp )date , date , )char *(0
اولین آرگومان برای execlpاسم فايل فرمان مي باشد ؛ ، execlpمسیر جستجو را از محیط شما (يعني PATHو )..استخراج مي کند
و جستجو را همانند شل انجام مي دهد .آرگومانهای دوم و بعدی اسم فرمان و آرگومانهايي برای فرمان مي باشند و اين آرگومانها ،
آرايه argvبرای برنامه جديد هستند .انتهای فهرست توسط يك آرگومان صفر علمت گذاری مي شود ( .برای آگاهي در خصوص
طرح exec)2( , execlpرا بخوانید ) .
فراخواني execlpبه برنامه موجودرا با برنامه جديد مي پوشاند ،آن را اجرا مي کند و سپس خارج مي شود .برنامه اصلي کنترل را
فقط زماني بر مي گرداند که يك خطا وجود داشته باشد .برای مثال ،اگر فايل نتواند يافت شود و يا قابل اجرا نباشد .
(execlp )date, date , )char*(0
;fprintf )stderr , couldn't execute date \n
233/322 محیط برنامه سازی لینوکس
;(exit )1
يك گونه از execlpبا عنوان execupزماني مفید است که شما به طور پیشرفته نمي دانید که چند آرگومان ،بايد وجود داشته باشند .
فراخوان عبارت از :
;(Execvp )filename , argv
در اينجا ، argp ،يك آرايه از اشاره گرها برای آرگومانها مي باشد (مانند ) argv؛ آخرين اشاره گر در آرايه ،بايد Nullباشد ،بنابراين
execvpمي تواند به ما بگويد که فهرست در کجا به پايان مي رسد .همانند execlpاسم فايل ،فايلي است که در آن برنامه يافت مي
شود و ، argpآرايه argvبرای برنامه جديد مي باشد ؛ [ ، argp ]0اسم برنامه است .
هیچ کدام از اين زيربرنامه ها ،منجر به گسترش فراکاراکترهايي مانند > * <,و نقل قولها وغیره در فهرست آرگومان نمي شوند .اگر
شما چنین چیزهايي را مي خواهید ،برای راه اندازی برنامه bin/sh/در شل ،از execlpاستفاده کنید ،که همه کار را انجام مي دهد .
يك سطر فرمان رشته ای بسازيد که شامل فرمان کامل باشد ،همچنانکه در پايانه تايپ شده است ،سپس بگوئید :
; )Execlp )/bin/sh , sh , -c , comrnadline, )char* ( 0
آرگومان – cبه عنوان سطرفرمان کامل با آرگومان بعدی رفتا مي کند ،نه به عنوان يك آرگومان تنها .
به عنوان يك شرح از execو برنامه waitfileرا در نظر بگیريد .فرمان & ]wait file filename ]command
به طور متناوب ،فايل نامگذاری شده را کنترل مي کند .اگر اين فايل تا آخرين زمان بدون تغییر باقي بماند ،فرمان اجرا مي شود .اگر
هیچ فرماني مشخص نشود ،فايل برای خروجي استاندارد کپي مي شود .ما از wailfileبرای کنترل پیشرفت troffاستفاده مي کنیم ،
مانند
& & wait file troff . out echo troff done
اجرای ، wait fileاز fstatبرای استخراج زماني که فايل برای آخرين بار تغییر کرده است ،استفاده مي کند .
/* wait file : wait until file stops changing*/
># include <stdio.b
># include <sys/types.h
># include <sys/stat.h
; char * progname
(main)argc,argv
; int argv
; [ ] char *argv
}
; int fd
; struct stat stbuf
;time-t old - time = 0
مرحله بعدی بدست آوردن مجدد کنترل پس از اجرای يك برنامه با execlpيا execbpمي باشد .چون اين زير برنامه ها ،به سهولت
،برنامه جديد را بر روی قبلي مي پوشانند ،برای ذخیره برنامه قبلي لزم است که اين برنامه در ابتدا به دو کپي تقسیم شود يکي از آنها
مي تواند پوشانده شود ،در حالیکه کپي ديگر ،منتظر برنامه جديد باقي مي ماند و برنامه را تا پايان مي پوشاند .تقسیم توسط يك
سیستم فراخوان با عنوان forkانجام مي شود :
; ( )Proc-id=fork
برنامه را به دو کپي تقسیم مي کند و هر دوی آنها اجرا مي شوند .تنها تفاوت بین اين کپي ،مقدار بازگردانده شده توسط forkمي
باشد . process-id ،در يکي از اين فرآيندها )proc – id )child ،صفر مي باشد .در فرآيند ديگر )proc - id ,)parentمقداری غیر
از صفر مي باشد اين فرآيند process - idبچه مي باشد .بنابراين روش اصلي برای فراخواني هربازگشت از برنامه ای ديگر عبارت
است از :
( If )fork ) ( = = 0
;(Execlp )/bin /sh, sh , c , command line , )char *(o
درحقیقت به جز برای کارکردن با خطاها ،اين روش ،مناسب مي باشد fork .روکپي از برنامه مي سازد .در بچه ،مقدار بازگردانده
شده توسط forkصفر است بنابراين execlpرا فرا مي خواند که سطر فرمان را انجام مي دهد و سپس حذف مي شود .
در والد fork ،مقدارغیر از صفر را باز مي گرداند ،در نتیجه از execlpپرش مي کند (اگر خطايي وجود نداشته باشد fork ، 1- ،را بر
مي گرداند) .
اغلب ،والد ،منتظر مي ماند تا بچه به پايان برسد ،قبل از اينکه خودش ادامه دهد چنین چیزی با فراخواني سیستم waitانجام مي شود
235/322 محیط برنامه سازی لینوکس
:
; Int status
(If )fork ) ( = = 0
;(Execlp )000 /*child */
;( Wait )&status /*purent*/
چنین چیزی ،هیچ کدام از موقعیتهای غیر عادی مانند خرابي execlpيا forkرا بکار نمي برد و احتمال ممکن است بیش از يك بچه
به طور همزمان اجرا شود )process-id , wait( .از بچه پايان يافته را بر مي گرداند .اگر شما بخواهید ،آن را توسط forkدر مقابل
مقدار بازگردانده شده ،کنترل کنید ) .در آخر ،اين بخش به هیچ کدام از رفتارهای عجیب ازطرف بچه نمي پردازد .هنوز اين سه
سطر ،قلب تابع استاندارد systemمي باشند .
Statsبازگردانده شده توسط waitتصور سیستم را در خصوص وضعیت خروجي بچه به 8بیت پائین مرتبه آن ،رمز گذاری مي کند
و اين میزان برای اتمام عادی صفر و برای نشان دادن انواع متعدد از مشکلت صفر مي باشد 8 .بیت بزرگتر بعدی ،از آرگومان
فراخوان برای exitگرفته مي شوند و يا از mainکه منجر به اتمام فرآيند بچه مي شود ،باز مي گردند .
زماني که يك برنامه توسط شل فراخوانده مي شود ،سه توصیف گر فايل صفر و يك و دو ،با اشاره به فايلهای صحیح تنظیم مي شوند
و ساير توصیف گران فايل در دسترس برای استفاده هستند زماني که اين برنامه برنامه ای ديگر را فرامي خواند ،تشريفات صحیح ،
اطمینان مي دهد که همان شرايط حفظ مي شوند .نه forkو نه ، execبه هیچ وجه بر فايلهای باز تاثیر نمي گذارند و هم والد و هم
بچه دارای فايلهای باز يکسان مي باشند .اگر والد ،خروجي ايي را میانگیر کند ،که بايد قبل از خروجي بچه ،خارج شود ،والد بايد
میانگیرهای خود را قبل از ، execlpخارج کند به طور معکوس ،اگر واد ،يك جريان ورودی را میانگیر کند ،بچه ،هر گونه اطلعاتي
را که توسط والد خوانده شده است ،رها مي کند .خروجي مي تواند خارج شود ،اما ورودی نمي تواند به تعويق بیفتد .هر دوی اين
بررسي ها مطرح مي شوند ،اگر ورودی ياخروجي با کتابخانه استاندارد I/Oکه در فصل 6توصیف شد ،انجام شود ،چون کتابخانه
استاندارد I/Oبه طور عادی هم خروجي و هم ورودی را میانگیر مي کند .
اين خصوصیت توصیف گران فايل در میان يكـ execipمي باشد که systemرا بشکنندـ :اگر برنامه فراخوان دارای ورودی يا
خروجي استاندارد متصل به پايانه نباشد ،هیچ کدام فرمان را با عنوان systemنمي خواهند .اين ممکن است چیزی باشد که خواسته
شود و در يك متن edبرای مثال از متن بیايد .حتي edبايدورودی خود را به صورت يك کاراکتر در يك زمان بخواند ،برای اينکه
از مشکلت میانگیر ساز ورودی جلوگیری کند .
اما برای برنامه های برهم کنشي مانند system ,pبايد مجددا ورودی و خروجي استاندارد را به پايانه متصل کند .يك راه برای اين کار
،متصل کردن آنها به dev/tty/مي باشد.
فراخوان سیستم )dup)fو توصیف گر فايل fdرا برروی توصیف گر فايل دارای پائین ترين شماره و تخصیص نیافته ،کپي مي گیرد
يك توصیف گر جديد را که به همان فايل باز استناد مي شود ،باز مي گرداند .اين رمز ،ورودی استاندارد يك برنامه را به فايل متصل
مي کند :
;In fd
; (Fd = open )file , 0
; (Close )0
; (Clup )fd
; (Close )fd
، )Close )0توصیف گر فايل صفر و ورودی استاندارد را آزاد مي سازد ،اما در حالت معمول ،بر والد تاثیر نمي گذارد .
236/322 محیط برنامه سازی لینوکس
برای پیامدهای خطاprogname ) برای برنامه های برهم کنشي وجود دارد ؛ اين نسخه ازsystem( دراين جا نسخه ما از سیستم
. ناديده بگیرند ما در بخش بعد به آنها مي پردازيم. شما بايد بخشهايي از تابع را که به علمت ها مي پردازند. استفاده مي کند
/*
*safer vesion of system for interactive programs
/*
# include <sigul.h>
# include <stdio.h>
system )s( /*run command lines */
char*s ;
}
int status >,pid ,w ,tty ;
int )*istat() ( , )*qstat () ( ;
extern char * progname ;
fflush )stdout(;
tty= open )/dev/tty , 2(;
if )tty= = -1(}
fprintf )stderr,%s : can't open /dev/tty\n , progname(;
return-1;
{
if ))pid = fork )1( = = 0(}
close )0( ; dup )tty( ;
close )1(; dup )tty( ;
close )2( ; dup )tty( ;
close )tty( ;
execlp )sh , sh ,-c , s , )char *(
exit )127( ;
{
close )tty( ;
istat = signal )SIGNT , SIG -1 GN( ;
qstat = signal)SIGQUIT , SIG- IGN(;
while ))w=wait )&status((! = pid &&w! = -1(
{
close )tty( ;
istat = signal )SIGNT , SIG-!GN(;
q stat = signal )SIGQUIT , SIG - ICN(;
while)) w= wait )cstatus(( ! = pid&& w! = -1(
;
if )w = = -1(
status = -1 ;
signal )SIGINT , istat(;
signal )SIGQUIT ,gstat(;
return stats ;
{
برای تشکیل خروجي و ورودیdup ed خواندن و نوشتن – و سپس با. باز مي شود2 با حالتdev / tty/ توجه داشته باشید که
زماني که شما دارد آن، ورودی و خطای استاندارد را مونتاژ مي کند، اين دقیقا روشي است که سیستم خروجي. استاندارد باز مي شود
237/322 محیط برنامه سازی لینوکس
مي شود .بنابراين ،خروجي استاندارد شما ،قابل نوشتن مي باشد :
& echohello 1>&0
hello
&
مفهوم آن اين است که ما مي توانیم توصیف گر 2از فايل dup'edرا برای اتصال مجدد ورودی و خروجي استاندارد داشته باشیم ،اما
بازکردن dev/tty/تمیز تر و ايمن تر است .حتي اين systemدارای مشکلت بالقوه مي باشد :فايلهای باز درشماره گیرنده مانند tty
در زير برنامه ttyinدر pاز فرآيند بچه عبور خواهند کرد .
درس در اينجا اين نیست که شما بايد از نسخه systemما برای همه برنامه های خود استفاده کنید -برای مثال به اين نسخه edغیر
برهم کنش را مي شکند – اما درس اين است که شما درك کنید چگونه فرآيندها کنترل مي شوند و از موارد اولیه به درستي استفاده
مي کنند و معني «به درستي » با کاربرد فرق مي کند و ممکن است موافق با اجرای استاندارد systemنباشد .
اين بخش در رابطه با چگونگي پرداختن به علئم(مانند وقفه ه ا ) به طور دقیق ،از دنیای خارج و با اشکالت برنامه مي باشد .
اشکالت برنامه اساسا از مراجع غیر مجاز حافظه ،اجرای ساختارهای ويژه يا خطاهای ممیز شناور بوجود مي آيند .عمومي ترين
علئم دنیای خارج ،وقفه مي باشد که زمان فرستاده مي شود که کاراکتر DELتايپ مي باشد و خارج شدن ازبرنامه که توسط کاراکتر
( ctl -1 (FSبوجود مي آيد ؛ گیرماندگي که با گیرماندن تلفن بوجود مي آيد و پايان دادن که با فرمان killبوجود مي آيد .زماني که
يکي از اين وقايع رخ مي دهد ،علمت به همه فرآيندهايي فرستاده مي شود که از همان پايانه آغاز شدند و مگراينکه ساير آرايش ها ،
ساخته شده باشند ،علمت به فرآيند خاتمه مي دهد .برای اکثر علئم ،يك فايل تصوير حافظه اصلي ،برای خطا زدايي بالقوه نوشته
مي شود ( )sdb)1( adb)1را مشاهده کنید ) .
علمت فراخواني سیستم ،عملکرد پیش فرض را تغییر مي دهد .اين علمت دارای دو آرگومان مي باشد .اولین آرگومان ،عددی
است که علمت را مشخص مي کند .دومین آرگومان ،آدرس يك تابع و يا رمزی مي باشد که درخواست مي کند ،علمت ناديده
گرفته شود يا به عملکرد پیش فرض ارائه شود .فايل > <signal .hشامل تعاريفي برای آرگومانهای متعدد مي باشد .بنابراين :
># include <signal.h
………….
; (Signal )SIGINT , SIG-IGN
منجر به ناديده گرفته شدن وقفه ها مي شود در حالیکه
; (Signal )SIGINT , SIG - DEL
عملکرد پیش فرض خاتمه فرآيند را مجددا ذخیره مي کند .در همه موارد ، signal ،ارزش قبلي علمت را باز مي گرداند .اگر دومین
آرگومان برای ، signalنام يك تابع باشد (،که بايد دقیقا در همان فايل مبدا اعلن شده باشد ) .تابع فراخوان مي شود ،زماني که
signalرخ مي دهد .عموما اين روش به اين منظور استفاده مي شود که برنامه کار ناتمام را قبل از اتمام پاك کند ،برای مثال يك فايل
موقت را حذف کند .
># include < signal-h
;char * tempfile = temp .xxxxxy
main)1
238/322 محیط برنامه سازی لینوکس
}
; ( ) extern onintr
(if )signal )SIGINT , SIG-1 GN( ! = SIG-IGN
; (signal )SIGINT , onitr
;(mktemp)tempfile
/*process...*/
; (exit )0
{
onitr ) ( /*clean up if interrupted */
}
; ( unlike )tempfile
; (exit )1
}
چرا فراخواني آزمون double testبرای signalدر pmainبه خاطر بیاوريد که علئم ،به همه فرآيندهای آغاز شده از يك برنامه ،به
صورت غیر برهم کنشي (با & آغاز مي شود ) اجرا مي شود ،شل به گونه ای مرتب مي شود که برنامه ،وقفه ها را ناديده بگیرد ،
بنابراين شل توسط وقفه های مورد نظر برای فرآيندهای پیش زمینه متوقف نمي شود .اگر اين برنامه با بیان اين موضوع آغاز شود که
همه وقفه ها بدون توجه به اينکه تلش شل را برای حمايت از آن ،زماني که در زمینه اجرا مي شود بي اثر مي سازند ،به زير برنامه
onitrفرستاده خواهد شد .
راه حل نشان داده شده در بال ،آزمايش الت استفاده از وقفه و تداوم آن برای ناديده گرفتن وقفه ها مي باشد ،اگر آنها ناديده گرفته
مي شوند .رمز همانگونه که نوشته مي شود ،به اين واقعیت بستگي دارد که signalحالت قبلي يك علمت خاص را باز مي گرداند .
اگرعلمتها ،ناديده گرفته شوند ،فرآيند بايد برای ناديده گرفتن آنها ادامه يابد درغیر اين صورت ،آيا بايد متوقف شوند .
يك برنامه پیشرفته تر ممکن است بخواهد يك وقفه را نگاه دارد و آن را به عنوان يك درخواست برای متوقف کردن چیزی بکار برد
که انجام مي شود و آن را به حلقه پردازش فرمان خود بازگرداند .به يك ويراستار متن فکر کنید :متوقف کردن يك خروجي چاپي
بلند نبايد منجر به خروج آن شود و کاری را که قبل انجام شده است ،از راست بدهد .رمز برای اين مورد ،مي تواند به اين صورت
نوشته شود :
># include <signal.h
># include <sp-timp.h
; jmp -buf sjbuf
( )main
}
; ( ) int onitr
(if )signal )SIGINT , SIG-IGN(!=SIG-IGN
;(signal /)SIGINT , onitr
setjmp )sjbuf(; /* save cvrrent stack position */
} (; ;) for
/* main processing loop * /
{
………….
{
onitr ) ( /*reset ifinterrupted */
}
239/322 محیط برنامه سازی لینوکس
در نظر بگیريد که وقفه ها را مي گیرد و نیز شامل يك شیوه (مانند «!» در ) edمي باشد و به موجب آن ساير برنامه ها مي توانند اجرا
شوند .سپس رمز ،مي تواند چیزی شبیه به رمز زير به نظر برسد .
(If )fork ) ( = = 0
; (Execlp )...
Signal )SLGINT , SIG-IGN(; /*parent ignores interrupts */
Wait )& status ( ; /*until child is doen */
Signal )SIGINT , onitr(; /* restore interrupts */
چرا اينگونه است ؟علئم به همه فرآيندهای شما فرستاده مي شود .فرض کنید برنامه ای که شما فرامي خوانید ،وقفه های خود را مي
گیرد ،همانند کاری که ويراستار انجام مي دهد .اگر شما برنامه فرعي را متوقف کنید ،علمت را مي گیرد و به حلقه اصلي خود باز
مي گرداند و احتمال پايانه شما را مي خواند .اما برنامه فراخوان نیز برای برنامه فرعي و خواندن پايانه شما از waitخود خارج مي
شود .داشتن دو فرآيندی که پايانه شما را مي خوانند ،بسیار گیج کننده است ،چون در واقع ،سیستم يك سکه را پرتاب مي کند برای
اينکه تصمیم بگیرد چه کسي بايد وارد هر سطر از ورودی شود .راه حل اين است که برنامه والد ،وقفه را ناديده بگیرد تا جايي که
بچه انجام مي شود .اين استدلل در بکارگیری علمت در ، systemمنعکس مي شود :
># include <signal -h
sgstem )s( /*run command line */
; char * s
}
; int status , pid .w,tty
; () (int )*istat( ) (, )*qstat
…….
} ( If ))pid = fork ) (( = = 0
….
; (Execlp )sh , sh , -c , s )char *(0
; (Exit )127
{
…..
;(istat = signal )SIGINT , SIG-IGN
;(qstat = signal )SIGQBIT , SIGIGN
while ))w = wait )&status (( ! = pid&& w ! =-1
;
(if )w = = -1
; status = -1
;(signal )SIGINT , istat
;(signal )SIGQVIT , qstat
; return status
}
جداي از اين اظهارات ،تابع signalبه طور بديهي داراي يك آرگومان ثانويه عجيب مي باشد .
اين آرگومان در حقيقت يك اشاره گر به تابعي است كه يك عدد صحيح را دريافت مي كند و
همچنين تايپ خود زير برنامه signalمي باشد .دو ارزش SIG- DFL , SIG – LGNداراي تايپ
صحيح مي باشند اما انتخاب مي شوند و در نتيجه با هيچ كدام يك از تابعهاي واقعي ممكن
تلق ندارند .براي افراد شايق در اينجا چگونگي تعريف آنها براي VAX , PDP-11وجود دارد ؛
تعاريف بايد تا جايي نگران كننده باشند كه ما را تشويق به استفاده از > <signal.hكنند .
241/322 محیط برنامه سازی لینوکس
هشدارها
فراخواني سیستم )alarm)nباعث مي شود که يك علمت SIGALRMبه فرآيند شما پس از چند ثانیه فرستاده مي شود .علمت
( alarmهشدار ) مي تواند برای اطمینان يافتن از اينکه چیزی درمیزان زمان رخ مي دهد ،استفاده شود ؛اگر چیزی اتفاق بیفتد ،علمت
alarmمي تواند خاموش شود ،اما اگر خاموش نشود ،فرآيند مي تواند کنترل را مجددا با گرفتن علمت alarmبدست آورد .
برای شرح ،دراين جا يك برنامه با عنوان time outوجود دارد که فرمان ديگر را اجرا مي کند ؛ اگر آن فرمان ،توسط زمان مشخص
شده ،پايان نپذيرد ،لغو مي شود .زماني که alarmقطع مي شود .برای مثال – فرمان watch forاز فصل 1را به خاطر آوريد .به
جای اينکه اين فرمان به طور نامحدود اجرا شود ،شما بايد يك محدوديت زماني را تنظیم کنید :
& & time out - 3600 wathcfor dmg
رمز در time outتقريبا هر چیزی را که ما در خصوص آن در دو بخش گذشته صحبت کرديم شرح مي دهد .بچه ايجاد مي شود والد
يك alarmرا تنظیم مي کند و سپس منتظر به پايان رسیدن بچه باقي مي ماند .اگر alarmدر ابتدا ظاهر شود ،بچه حذف مي شود .
يك تلش برای بازگرداندن وضعیت خروجي بچه انجام مي شود .
/* time out : set time limit on a process */
># include <stdio .h
># include <signal .h
intpid ; /* child process id */
;char * progname
(main )argc , argv
; intargc
; [ ] char* argv
}
; ( ) int sec = 10 , status , on alarm
; [progname = argv ]0
}(if )argv>1&& argv] 1[ ]0[= = -
; [ sec = atoi )&&rgv ]1[ ]1
; argc --
;argv ++
{
(if )argc <2
;( error )usage . % s ] 10[command , progname
} ( if ))pid = fork )1( = = 0
; [execvp cargv ]1[ ,& argv ]1
; [error )couldn’t start % s ,argv ]1
{
;(signal )SIGALRM , onalarm
;(alarm )sec
(if )wait)status ( = = -1 : : )statis & 0177 (!= 0
; [error )% s killed , argv] 1
;(exit ))status ((8( & 0377
242/322 محیط برنامه سازی لینوکس
{
onalarm )( /* kill child when alarm arrives */
}
;( kill cpid , SIC KILL
{
تمرين . 7-18آيا شما مي توانید استنباط کنید که چگونه SLEEPاجرا مي شويد ؟ توچه )PAUSE )2تحت چه شرايطي اگر
شرايطي وجود ندارد آيا alarm , sleepمي توانند با يکديگر تداخل شوند ؟
توصیف کاملي در خصوص اجرای سیستم يونیکس وجود ندارد ،تا حدودی به خاطر اينکه ،رمز ،باز مي باشد .مقاله اجرای يونیکس
از کن تامپسون ، 1978( ،جولی ) BSTJموضوعات مهم را شرح مي دهد .ساير مقالتي که موضوعات مربوط را شرح مي دهند « ،
مقاله سیستم يونیکس – يك مقاله بازنگرانه در همان موضوع ]BSTو ارزيابي سیستم اشتراك زماني يونیکس (سمپوزيوم در خصوص
متولوژی برنامه نويسي و طرح زبان ،نکات مربوط به سخنراني اسپرينگر – ورلگ در خصوص علم کامپیوتر ) 1979 ، 79مي باشند
که هر دو نوشته دنیس ريتچای هستند .
برنامه ، readslowتوسط پیترمرينبرگ ،به عنوان يك روش اضافهي پائین برای ماشاگران به منظور تماشای پیشرفت ماشین شطرنج بل
،کن تامپسون و جوکاندون در طول مسابقات شطرنج ،اختراع شد .
بل ،وضعیت بازی خود را در يك فايل ثبت کرد و تماشاگران فايل را با readslowبدست آوردند ،به گونه ای که بسیاری از چرخه
های قبلي را از طرح بل نگیرد ( .جديدترين نسخه سخت اقرار بل ،محاسبه اندکي را بر روی ماشین میزبان خود انجام مي دهد ،
بنابراين مشکل بطرف شده است ) .
فکر بکر bبرای spnameاز تام داف مي آيد .يك مقاله توسط ايوردارهام ،ديويد لمب و جیمز ساکس که تصحیح تلفظ را در واسطه
های کاربر مجاز کرد ، CACM ،اکتبر ، 1983تا حدودی طرح متفاوتي را برای تصحیح تلفظ ،در متن يك برنامه پستي ارائه مي دهد
.
243/322 محیط برنامه سازی لینوکس
اين بخش توليد hoc 1را توضيح مي دهد و اين برنامه ،برنامه اي است كه تواناييهاي
معادل يك ماشين حساب جيبي با امكانات محدود را فراهم مي كند و البته به راحتي آن
حمل نمي شود .اين برنامه فقط چهار تابع / ، × ، - ، +را دارد ( به علوه پرانتز را هم كه
مي تواند به دلخواه وارد عبارت شود شامل مي شود ) كه ماشين حسابهاي جيبي با
قابليتهاي محدود ارائه مي دهندت .اگر پس از يك عبارتت RETURNتايپ كنيد ،جواب
حاصل در خط بعد چاپ خواهد شد.
245/322 محیط برنامه سازی لینوکس
-قواعد ( )grammars
از زمانيكه فرم Backus- Naurبراي Algolبه وجود آمد ،زبانها باقواعد منطقي بيان شده
اند .قواعد hoc 1در نمايش اختصاري شان كوچك وساده اند .
list : expr \n list
expr \n
expr: NUMBER
expr + expr
expr - expr
expr * expr
expr / expr
()expr
چنانکه از مجموعه عبارات فوق برمي آيد list ،تناوبي از عباراتي است که درخطوط مجزا به دنبال هم مي آيند .هر عبارت شامل يك
عدد يا يك جفت عبارت که توسط يك اپراتور به هم مرتبطند و يا کي عبارت داخل پرانتز مي شود .
اين برنامه کامل نیست .روال اولويت را در میان برنامه های مختلف و نیز ارتباط اپراتورها را مشخص نمي کند .در ضمن هیچ معني
را به مفاهیم ( )constractsنمي بخشد .يا اينکه listبا استفاده از exprو exprبا استفاده از NUMBERبیان مي شود ،اما خود
NUMBERهیچ جا بیان نمي شود .
اين جزئیات بايد وارد شوند تا از يك طرح اولیه زبان به يك برنامه کاری برسیم .
بازنگري :yacc
yaccيك مولد جداکننده است .به اين معني که yaccبرنامه ای برای تبديل بیان گرامری (قاعده ای ) ،نظیر آنچه در برنامه بال آمده ،
به يك جداکننده که عبارات داخل زبان را جدا مي کند مي باشد yacc .روشي برای ارتباط معاني با اجزاء گرامری فراهم مي کند که
همانطور که عملیات تجزيه رخ مي دهد ،معني هم برآورد شود .مراحل استفاده از yaccبه ترتیب زير است:
ابتدا ،قاعده ای مشابه به آنچه در بالی صفحه آمده است اما دقیق تر نوشته مي شود .اين قاعده ترکیب ( )syntaxزبان را مشخص مي
کند yacc .مي تواند در اين مرحله جهت هشدار برای خطاها و بروز شك در گرامر به کار رود .
در مرحله دوم ،هر گرامر يا محصول آن مي تواند با يك عمل ( )actionتوسعه يابد .عمل
عبارتي است كه بيان مي كند زماني كه يك فرم گرامري خاص در برنامه اي كه در حال
تجزيه است يافت شد چه عمل خاصي انجام شود .اين عمل خاص به زبان cنوشته مي
شود و با تبديلتي گرامر را به زبان cارتباط مي دهد .اين مرحله ( )semanticمعناي زبان
را تعيين مي كند .
246/322 محیط برنامه سازی لینوکس
در مرحله سوم ،يك تحليل گر واژه مورد نياز است .اين تحليل گر بايد ورود جايي را كه در
حال تجزيه هستند بخواند و آنها را به قطعات ( )chunksمعني داري براي تجزيه گر بشكند
.يكت NUMBERمثالي از يك قطعه واژه اي به طول چند كاراكتر استت .اپراتورهاي تك
كاراكتري نظير * ، +نيز قطعه هستند .يك قطعه واژه اي يك نشانه ( )to kenناميده مي
شود .
نهايتًا ،يك برنامه مستقل ( )routineكنترل كننده جهت فراخواني تجزيه گر كه توسط yacc
ساخته مي شود مورد نياز استت 4yacc .گرامر عمليات معنايي را به يك تابع پردازنده
تبديل مي كند .اين تابع yyparseناميده مي شود و به صورت فايل cنوشته مي شود .
اگر yaccهيچ خطايي پيدا نكند ،پردازنده ،تحليل گر واژه و برنامه مستقل كنترل كننده
ل در ارتباط با ساير برنامه هاي مستقل cو اجرا شوند . مي توانند كامپايل و احتما ً
اجراي اين برنامه عبارتست از فراخواني مكرر تحت تحليل گر واژه اي براي نشانه ها ،
درك ساختار گرامري در ورودي و اجراي عمليات معنايي به موازات اينكه هر قانون گرامري
درك مي شود .ورودي به تحليل گر بايد yylexنام بگيرد زيرا هر بار yyparseاين تابع را فرا
مي خواند ،نشانه جديدي مي خواهدت ( .اساميت كه درت yaccاستفاده مي شود بات y
شروع مي شود .به بيان دقيق تر ورودي yaccفرم زير را مي گيرد .
}%
C statements like#include, declarations , etc. This section is optional.
{%
yacc declaration: lexical tokens ,grammar variables,
precedence and associativity information
%%
grammer rules and actions
%%
more C statements )optional(:
{ main )( }. . .; yyparse ) ( ;. . .
} yylex )( }. . .
اين فرم با yaccاجرا مي شود و نتیجه در فايلي به نام y.tab.cبا چیدمان زير نوشته مي شود .
C statements form between%}and%{, if any
C statements from after second %% , if any:
{ …; ( ) Main) ( } … ; yyparse
{ … } ( ) Yylex
ت مي سازد ،طريقه معمول 0 اين مورد كه yaccيك فايل Cبه جاي فايل كامپايل شده
yacc . 4از ------- yet another comilerگرفته شده است .اين مورد ،توصیفي توسط نويسنده اش ، Steve Johnsonبرروی تعدادی از برنامه هايي که در زمان
تولید yaccوجود داشت (حدود )1972مي باشد .
247/322 محیط برنامه سازی لینوکس
برخورد يونيكس استت .اين تشيوه كه در آن توليد شده قابل حمل و انتقال به تساير
فرآيندهاست منعطف ترين شيوه ممكن است .خود yaccابزاري قدرتمند است .لذا هر
چند ممكن است آموختن yaccتلش زيادي را بطلبد اما نتيجه مثبت اين تلش به دفعات
ديده مي شود .تجزيه گرهايي كه با yaccتوليد مي شوند ،كوچك ،كارآ و صحيح هستند
( .هرچند صحت عمليات معنايي برعهده خود شماست ) .با بسياري از مشكلت واضح
تجزيه اتوماتيك برخورد مي شود .برنامه هاي شناخت زبان براحتي ساخته مي شوند و
(مهمتر اينكه ) به موازات پيشرفت بيان زبان به كرات قابل اصلحند .
كد مرجع براي hoc1شامل گرامري به همراه عمليات ،يك برنامه مستقل واژه اي و يك
mainمي باشد كه همگي در فايل hoc.yقرار دارندت ( .اسامي ت فايلهاي yaccبهت yختم
مي شوندت .اما اين نحوه نامگذاري مرسوم ،برخلفت ccو cبا خودت yaccتحصيل تنمي
شود ) .بخش گرامري ،نيمه اول hoc.yاست :
اطلعات جديد زيادی در اين خطوط وارد شده است .قصد نداريم که هر جزئیات اين بخش را توضیح دهیم و همچنین قصد نداريم
نحوه عمل تجزيه گر را بیان کنیم .برای کسب اطلعاتي در اين زمینه مي توانید به راهنمای yaccمراجعه کنید .
قوانين يك درميان با Iجدا مي شوند .هر قانون گرامري مي تواند عمل مربوط به خود را
داشته باشد .اين قانون زماني اجرا مي شود كه نمونه اي از آن در ورودي شناسايي
شود .يك عمل ،مجموعه اي از عبارات cاست كه در براكت قرار گرفته اند . }and{ .با
يك تعمل ت،ت ( $nمانندت $1ت،ت ، $2ت ) ...دال تبرت تمقداري تاست تكهت تبهت توسيلةت nامين تجزء
248/322 محیط برنامه سازی لینوکس
برگردانده مي شود و $$مقداري است كه به عنوان مقدار كل قانون برگردانده مي شود .
بنابراين به عنوان مثال ،در قانون
' '
است ،مقدارت ، exprمجموع مقادير دو جزءت exprاست .توجه كنيد كهت ¿ $ 2 ,¿ت است .
هرجزء شماره گذاري مي شود .
در سطحي بالتر ،سطر جديديت ¿ { n تبه عبارت افزوده مي شود ،به عنوان يكت list
' '
شناساييي شده و مقدار آن چاپ مي شودت .اگر آخر ورودي ساختار اينچنيني داشته
باشد ،فرآيند تجزيه به وضوح متوقف مي شود .يك listممكن است يك رشته ()string
خالي باشد .به اين ترتيب به خطوط ورودي خالي نيز عمل مي شود .
وروديت yaccفرم خاصي نداردت .فرمي كه ما استفاده مي كنيم ،فرمت توصيه شده
استاندارد استت .در اين چنين صورت ،عمل شناسايي با تجزيه ورودي ،برآورد فوري
عبارت را نيز به همراه دارد .در موارد پيچيده تر (شامل hoc 4و نسخه هاي پس از آن ) ،
فرآيند تجزيه براي اجراهاي بعدي كه توليد مي كند .بهتر است كه تجزيه را به صورت يك
درخت تجزيه ( )parse treeمشابه شكل 1-8تصوير كنيم ومقادير را به صورتي كه محاسبه
مي شوند و از برگهاي اين درخت به سمت ريشه رشد مي كنند ببينيم .
249/322 محیط برنامه سازی لینوکس
Yyparse,mainرا جهت تجزيه ورودی فرا مي خواند .کل حلقه از يك عبارت به عبارت بعد با استفاده از گرامر و به کمك مجموعه
ای از محصولت listانجام مي گیرد .
قرار دادن يك حلقه اطراف فراخواني yyparseدر mainو داشتن عملي برای listکه مقدار را چاپ کند و فوراً برگرداند نیز به همین
میزان قابل قبول خواهد بود .
در عوض yylex,yyparseرا به كرات براي ورودي نشانه ها فرا مي خواند yylex .ما ساده
است .اين فايل blankها tab ،ها را رد مي كند و رشته هاي اعداد را به يك مقدار عددي
تبديل مي كند ،خطوط ورودي را براي گزارش خطا شمارش مي كند و ساير كاركترها را
به صورت خودشان برمي گرداند .از آنجا كه گرامر تنها انتظار دارد كه \ +,-,* ΄΄,/,,(,),nرا
ببينيد ،ساير كاركترها سبب مي شود كه yyparseپيغام خطايي بدهد .بازگرداندن صفر
،سيگنال “end – fileرا به yyparseمي فرستد.
متغیر yyl valبرای ارتباط بین تجزيه گر و تحلیل گر واژه ای استفاده مي شود .اين متغیر به وسیله yyparseمشخص مي شود و
نوعي مشابه پشته yaccدارد yylex .نوع يك نشانه را به عنوان مقدار تابعي اش برمي گرداند و yylbvalرا به مقدار نشانه نسبت مي
دهد (،در صورت وجود) .به عنوان مثال نوع يك عدد اعشاری NUMBERو مقدار آن مثل ً 12/34است .برای بعضي نشانه ها
251/322 محیط برنامه سازی لینوکس
بخصوص تك کاراکترهايي نظیر ΄\ ΄+΄ , ΄nگرامر ،مقدار را استفاده نمي کند و تنها نوع را استفاده مي کند .در اين صورت yylval
نیازی به تنظیم و مقدارگذاری ندارد .
عبارتت yacc%token NUMBERبهت تيكت تدستورت تمشخصت تدرت تفايلت تخروجيت yaccبهت تنام
y.tab.cتبديل مي شودت .بنابراينت NUMBERهمه جا مي تواند به عنوان يكت ثابت تدر
برنامه cاستفاده شود yacc .مقاديري را كه با كاراكترهاي ASCIIمشابه نيستند انتخاب
مي كند .
اگر يك خطاي تركيبي وجود داشته باشد yyerror,yyparse ،را با يك رشته كه شامل يك
پيغام رمزي به صورت syntax errorاست فرا مي خواند .انتظار مي رود كه استفاده كننده
yaccيكت yyerrorايجاد كندت .استفاده كنندهت yaccما فقطت رشته ترا به تابع ديگري وتابع
اخطار ( )worningمنتقل مي كند كه اطلعات بيشتري را چاپ كند .نسخه هاي بعدي
hocاز اخطار مستقيمًا استفاده مي كنند .
به اين ترتیب پايان برنامه های مستقل در hoc.yتعیین مي شود .
کامپايل يك برنامه yaccيك فرآيند دومرحله ای است :
hoc 1 تمرينت ) 1-8ساختار فايلت y.tab.cرا امتحان كنيدت ( .اين فايل حدودت 300خط برايت
مي باشد ) .
252/322 محیط برنامه سازی لینوکس
قبلً ادعا كرديم كه استفاده ازت yaccايجاد تغيير در يك زبان را سهولت مي بخشدت .به
عنوان مثال ،اجازه بدهيد علمت منفي را به hoc 1اضافه كنيم ،به گونه اي كه عباراتي
نظير −3−4برآورد شوند و به عنوان خطاهاي تركيبي تلقي نشوند .
دقیقا ً دو خط بايد به hoc.yاضافه شود .يك UNARY MINUS tokenجديد به آخر بخش ابتدايي اضافه مي شود تا اينکه به
علمت منفي بیشترين اولويت را بدهد .
΄% left ΄+΄ ΄-
΄%left ΄*΄ ΄ /
%left UNARYMINUS / * new*/
به گرامر نیز يك محصول باری exprاضافه مي شود :
%precبیان مي کند که علمت منفي (قبل از عبارت ) اولويت ( UNARYMINUSبال) دارد .در اينجا عمل ،تغییر علمت است .
يك علمت منفي بین دو عبارت اولويت پیش فرض را مي گیرد .
تمرين )2-8اپراتورها ( %قدرمطلق يا باقيمانده ) و +قبل از عبارت را به hoc 1اضافه كنيد .
راهنمايي :به fr exp 3. 0مراجعه كنيد .
-انحرافي از make
تايپ دو دستور جهت كامپايل يك نسخه جديد hoc 1مشكل ساز است .هر چند ساخت
يك فايل پوسته ايت ( )shellبراي انجام كار راحت است اما روش بهتري نيز وجود داردت .
روشي كه در آن wiJIبه طور كلي تعيين مي كند كه چه زماني بيش از يك فايل منبع در
برنامه وجود دارد .برنامه مشخصه makeنحوه ارتباط اجزاء به يكديگر را فرا مي خواند .
اينت تبرنامهت تزمانهايي ترات تكهت تدرت تآنهات تاجزاءت تمختلف تآخرينت تبارت تاصلحت تشدهت تاندت تچكت تمي
كند،مقدار مينيمم كامپايل مجرد لزم براي ساختن يك نسخه جديد پايات ( )consistentرا
دركت تميت تكندت توت تسپست تفرآيندهات ترات تاجرات تميت تكندت make .همچنينت تپيچيدگيت تهاي
فرآيندهاي چند مرحله اي مثل yaccرا در مي يابد ،بنابراين اين موارد ت مي توانند
بدون اينكه تك تك مراحل خوانده شوند وارد مشخصه makeبشوند .
در ضمن ،زماني كه برنامه در حال توليد به اندازه كافي بزرگ است كه روي فايلهاي منبع
مختلفي تكشيده تشود ت،ت makeمفيدت تواقع تمي تشود ت،ت تهر تچندت تاين تبرنامه تحتي تبراي
فايلهايي به كوچكي hoc 1نيز مناسب است .در اينجا مشخصه makeبراي hoc 1آورده
شده است .در اينجا makeدر فايلي به نام makefileوارد شده است .
253/322 محیط برنامه سازی لینوکس
مرحله بعدت ( يك مرحله كوچكت ) افزودن حافظه بهت hoc 1تبراي ساختت hoc 2تاستت .
حافظه 26متغير است كه از aتا zنامگذاري مي شوند .اين مرحله خيلي رسمي نيست
اما يك مرحله مياني ساده و مفيد مي باشد .همچنين چند مورد بررسي خطا خواهيم
افزود .اگر hoc 1را امتحان كنيد ،متوجه مي شويد كه برخورد آن با خطاهاي تركيبي چاپ
كردنت تپيغامت توت تمتوقف تشدن تاست توت تاصلحت تخطاهاي تحسابي تمثلت تتقسيمت تبرت تصفحه
امكانپذير مي باشد .
$ hoc 1
1/ 0
Floating $ exception – core dumped
تغییراتي که برای اين موارد لزم است ساده بوده وحدود 35خط کد مي باشد تحلیل گر واژه ای ، yylexبايد حروف را به عنوان
متغیرها شناسايي کند .گرامر بايد محصولتي به فرم زير را در بربگیرد:
expr: VAR
Var ΄ =΄ expr
يك عبارت مي تواند رابطه ای را شامل شود که چند جايگزيني همزمان نظیر
X=Y=Z=0
254/322 محیط برنامه سازی لینوکس
Union declaration%بیان مي کند که المانهای پشته يك مضاعف (معمول ً يك عدد) و يا يك intرا نگه مي دارند که ايندکسي
برای حافظه آرايه است .به token declaration%با يك نشانه گر نوع اضافه شده است .
type declaration%تعیین مي کند که exprعضو > <valواحد است ،به اين معني که يك مضاعف اطلعات نوع به yaccاين
255/322 محیط برنامه سازی لینوکس
امکان را مي دهد که مراجعي برای تصحیح اعضای واحد تولید کند .همچنین توجه کنید که = ارتباط دهنده از راست است در حالیکه
ساير اپراتورها ارتباط دهنده از چپ مي باشند .
بررسي خطا در بخشهاي مختلف مي آيد .يك مورد واضح تستي است كه براي تقسيم
بر صفر انجام مي گيردت .اگر اين مورد رخ دهد يك برنامهت مستق خطا execerrorناميده
مي شود .
تست دوم گرفتن سیگنال ( floating point excaptionاستثناء عدد اعشاری) است که زماني رخ مي دهد که يك عدد اعشاری سرريز
کند )averflow(.اين سیگنال در mainتنظیم شده است .
بخش نهايي بازگشت از خطا ،افزودن يك محصول براي خطاست .خطا يك كلمه ذخيره
شده در يك گرامرت yaccاستت .اين كلمه راهي براي فهميدن و برگشتن از يك خطاي
تركيبي فراهم مي كند .اگر خطايي رخ دهد yacc .نهايتًا از يك محصول استفاده مي كند
،خطا را به عنوان مرودي كه از نظر گرامري درست است تلقي مي كند و برمي گردد .
عمل yyerrorkنشانه ( )flayرا در تجزيه گر تنظيم مي كند كه به آن اجازه بازگشت به يك
حالت تجزيه منطقي مي دهد .بازگشت از خطا در هر تجزيه گري مشكل است .بايد
توجه كرد كه در اينجا تنها مراحل ابتدايي را در نظر گرفته ايم و نيز به سرعت از روي
قابليتهايت yaccگذاشته ايمت .عمليات گرامريت hoc 2ت خيلي تغيير نمي كندت .در اينجا
mainاست كه به آن setjrpرا افزوده ايم تا يك حالت كاملً مناسب براي تكرار بعد از يك
خطا را ذخيره كند ، execerror .انطباقت longjmpرا انجام مي دهدت ( .به بخشت 5-7براي
توضيح longjmp,setjmpمراجعه كنيد ) .
براي اشكال زدايي ،لغو فراخواني execerrorمناسب است ( .به abort 3مراجعه كنيد )
كه به يك كپي هسته اي منجر مي شود كه مي تواند با adbيا sdbخوانده شود .زماني
كه برنامه نسبتًا قويتر است ،لغو يا longjmpجايگزين مي شود .خط جديد تحليل گر واژه
اي اختلف كوچكي در hoc 2است .يك تست اضافي براي حروف كوچك وجود دارد و از
256/322 محیط برنامه سازی لینوکس
آنجا كه yylvalيك واحد است ،عضو مناسب بايد قبل از اينكه yylexتنظيم شود ،برگردد .
در اينجا بخشهايي كه بايد تغيير كنند آورده شده اند :
ل )3/1416
مجدد ًا توجه کنید که چگونه نوع نشانه (به عنوان مثال ) NUMBERمتمايز از مقدار آن است ( .مث ً
در اينجا متغير و بازگشت از خطا را كه موارد جديدي در hoc 2هستند بيان كنيم :
در واقع ppp-IIساختار ويژه اي براي تشخيص سرريز عدد اعشاري دارد اما روي بيشتر
ماشينهاي ديگر hoc 2همانطور كه نشان داده شده عمل مي كند .
تمرين )3-8قابليتي براي حفظ جديدترين مقدار محاسبه شده اضافه كنيد به گونه اي كه
نيازي به تايپ مجدد در يكسري از محاسبات مرتبط نباشد .يك راه حل اين است كه از
طريق يكي از متغيرهاي makeعمل كنيم به عنوان مثال ΄ ΄pبراي ΄. previons΄-o
تمرين hoc )4-8را به گونه اي اصلح كنيد كه يك سمي كالن بتواند به عنوان يك خاتمه گر
عبارت عمل كند .معادل يك .newline-o
در اين نسخه ،نسخه ، hoc 3تعداد زيادي قابليت جديد و مقداري مرتبط با كد اضافي ،
افزوده مي شود .ويژگي جديد اصلي دسترسي به توابع داخلي زير است :
257/322 محیط برنامه سازی لینوکس
يك اپراتور توان نيز اضافه كرده ايمت .اين اپراتور بالترين اولويت را دارد و ارتباط دهنده از
راست استت .از آنجا كه تحليل گر واژه اي بايد بات اسهاي تداخلي بلندتر از يك كاراكتر
مواجه تشود ت،ت تسعي تدر تجهت تافزايش تطول تاسامي تمتغيرها تكار تبيهوده تاي تنيستت .
جداول عليم پيچيده تري براي ذخيره سازي مسير اين متغيرها خواهيم داشت .زماني
كه اين جدول را داشته باشيم مي توانيم آنرا با نامها و مقاديري براي بعضي ارتباطات
مفيد از پيش فراخواني كنيم .
رفتار را نيز تا حدي سازمانديه كرده ايم ت .در ، hoc 2رابطة x=exprنه تنها رابطه را ايجاد
مي كند ،بلكه مقدار را هم چاپ مي كند زيرا همه عبارات چاپ مي شوند .
$ hoc 2
x =2∗3.14159
6. 28318
Value printed for assignment to variable
در ، hoc 3تمايزي بين رابطه ها و عبارات ساخته مي شود ،مقادير تنها براي عبارت چاپ
مي شود .
$ hoc 3
x =2∗3.14159
x Assignment : no value is printed
6. 28318 : Expression
Valueمي آيد به اندازه کافي بزرگ است (حدود 250خط) که بهتر است به فايلهای جداگانه ای
تغییرات بدست برنامه ای که بعد ا ز همه اين
is printed
258/322 محیط برنامه سازی لینوکس
برای ويرايش ساده تر وکامپايل سريعتر شکسته شوند .اکنون 5فايل به جای يك فايل وجود دارد :
برای اين جداسازی بايد بیشتر راجع به اينکه چگونه يك برنامه چند فايلي Cرا سازماندهي کنیم و بیشتر راجع به makeبدانیم برای
اينکه بخشي از کار را برای ما انجام دهد .
به زودی به makeبرمي گرديم .در ابتدا اجازه دهید که به کد جدول علمت نگاهي بیندازيم .يك علمت ،نام ،نوع ( VARيا
)BLTINو يك مقدار دارد .اگر علمت Var،باشد ،مقدار يك مضاعف است .اگر BLTINباشد مقدار يك اشاره گر به تابعي است
که يك مضاعف برمي گرداند .اين اطلعات در hoc.y .symbol.c ،init.cمورد نیاز است .
مي توانستیم تنها سه کپي بسازيم اما زماني که يك تغییر ساخته مي شود احتمال اينکه اشتباه کنیم يا اينکه فراموش کنیم که يك کپي را
جديد کنیم بسیار زياد است .در عوض اطلعات معمول را در يك فايل سرآمد hoc.hقرار مي دهیم .هر فايلي که به اين فايل نیاز
داشته باشد آنرا وارد مي کند ( .پسوند hمرسوم است اما با هیچ برنامه ای تحصیل نمي شود ).همچنین به فال makeاين حقیقت را
که اين فايلها به hoc.hبستگي دارند اضافه مي کنیم به نحوی که زماني که تغییراتي رخ مي دهد کامپايل مجدد ًا انجام شود .
نوع VAR , UNDEFای است که هنوز يك مقدار به آن نسبت داده نشده است .عليمي که با هم در يك listمرتبط مي شوند ،دو
علمت قسمت nextرا استفاده مي کنند .
خود listبرای symbol.cمحلي است .تنها دسترسي به آن از طريق جستجو و نصب توابع است .اين روش ،تغییر به ساختار جدول
عليم را در صورت لزوم آسان مي سازد ( .يکبار آنرا انجام داده ايم list , lookup ).را برای دستیابي به يك na!Tieويژه جستجو مي
کند اگر اسم علمت را پیدا کند به آن يك اشاره گر برمي گرداند و در غیر اينصورت به آن صفر برمي گرداند .جدول علمت از
جستجوی خطي استفاده مي کند ،که از آنجايي که متغیرها تنها در طي تجزيه جستجو مي شوند و نه در حین اجرا کامل ً برای ماشین
حساب واکنشي ما مناسب است .
259/322 محیط برنامه سازی لینوکس
Installيكت تمقدارت ترات تبات تنوعت توت تمقدارت تمرتبطشت تدرت تباليتت listقرارت تميت تدهدت تتت .
, emalloc mallocو تخصيص دهنده ذخيره استاندارد را فرامي خواندت ( )<<malloc3و
نتيجه را چك مي كند .اين سه برنامه مستبقل محتواي symbol.cهستند .فايل y.tab.h
با اجرايت yacc.dتوليد مي شودت .اين فايل دستورت define #اي را كهت yaccبراي نشانه
هايي نظير ... ، VAR , NUMBER , BLTINتوليد كرده است ،شامل مي شود .
فايل init.cشامل تعاريفي برای ثوابت ( ).... ، PIو اشاره گرهای تابعي برای توابع داخلي است .اين موارد در جدول علمت به وسیله
260/322 محیط برنامه سازی لینوکس
داده ها به جای اينکه وارد کد شوند در جداول ذخیره مي شوند .زيرا فراخواني و ايجاد تغییر در جداول ساده تر است .از آنجا که
جداول تنها در اين فايل قابل مشاهده اند نه در کل برنامه ،جداول استاتیك نامیده مي شوند .بزودی به برنامه های مستقل رياضي
261/322 محیط برنامه سازی لینوکس
sqrt,logبرمي گرديم .با ساخت در محل ،مي توان تغییراتي در گرامری که از اين توابع داخلي استفاده مي کند ،ايجاد کرد
262/322 محیط برنامه سازی لینوکس
اکنون گرامر برای جايگزيني و ايجاد رابطه علوه بر asgn , exprدارد ؛ يك خط ورودی که فقط شامل
VAR expr
باشد يك جايگزين (رابطه) است و بنابراين هیچ تعدادی چاپ نمي شود .توجه کنید که افزودن توان به گرامر حاوی ارتباط دهنده
راست آن ساده است .
پشته yaccيك واحد متفاوت دارد .به جای مراجعه به يك متغیر با ايندکس آن در يك جدول 26المانه ،يك اشاره گر به يك عنصر
نوع علمتي وجود دارد .فايل سرآمد ( ، header( hoc.cتعريف اين نوع را در برمي گیرد .
تحلیل گر واژه ای اسامي متغیر را مي شناسد ،آنها را در جدول علمت جستجو مي کند و تصمیم مي گیرد که آيا متغیر ( )VARاست
يا داخلي ( . )BLTINنوعي که با yylexبرمي گردد يکي از اينهاست .هم متغیرهای تعريف شده توسط کاربر و هم متغیرهای از
پیش تعريف شده مثل PIاز نوع VARهستند .يکي از خواص يك متغیر اين است که آيا به آن يك مقدار نسبت داده شده است يا
خیر ،بطوريکه استفاده از يك متغیر نامشخص مي تواند سبب ايجاد يك پیغام خطا توسط yyparseشود .تستي که تعیین مي کند آيا
يك متغیر مشخص شده است يا خیر بايد در گرامر باشد نه در تحلیل گر واژه ای .زماني که يك ، VARواژه ای تشخیص داده شود،
فضای آن هنوز مشخص نشده است .نمي خواهیم با اين اعتراض مواجه شويم که علیرغم اينکه فضای Xکامل ً مجاز است اما هنوز
مشخص نشده است ( .مثل سمت چپ رابطه يا نظیر )X==1
در اينجا بخش تصحیح شده yylexآورده شده است :
Mainيك خط اضافي دارد که برنامه مستقل ابتدای initرا مي خواند تا توابع داخلي اسامي از پیش تعیین شده مثل PIرا در جدول
علمت نصب کنند .
263/322 محیط برنامه سازی لینوکس
تنها فايل باقیمانده math.cاست .برخي از توابع رياضي استاندارد رابطي برای چك کردن خطا برای پیغام و بازگشت از آن نیاز دارند .
به عنوان مثال تابع sqrtدر صورتیکه آرلگانش منفي باشد به سادگي ،صفر برمیگرداند .کد در math.cتستهای خطای جلد 2راهنمای
برنامه نويس UNIXرا استفاده مي کند .برای اين منظور به فصل 7مراجعه کنید .اين روش قابل اعتماد تر و اجرايي تر از اين است
که خودمان تستها را بنويسم .زيرا محدوديت های خاص برنامه منطقاُ در کد ( afficialاصلي) به بهترين وجه منعکس مي شوند .
فايل سرآمد > <math.hتعاريف نوع برای توابع استاندارد رياضي را شامل مي شود <error.h> .اسامي خطاهايي را که يافت مي
شوند را در برمي گیرد .
264/322 محیط برنامه سازی لینوکس
زماني که yaccرا روی گرامر جديد اجرا مي کنیم يك تشخیص غیرگرامری جالب رخ مي دهد:
$ yacc hoc.y
Conflicts: 1 shift/reduce $
پيغام shift /reduceبه اين معني است كه گرامر ، hoc 3مبهم است :تك خط ورودي
X=1
به دور روش مي تواند تجزيه شود :
265/322 محیط برنامه سازی لینوکس
تجزيه گر يا بايد تصمیم بگیرد که asgnبه يك exprو سپس به يك ، listدر قسمت چپ درخت تجزيه گر ،کاهش يابد يا اينکه
تصمیم بگیرد n/بعدی shiftو انتقال را فوراً استفاده کند و همه را به يك listبدون قانوني میاني در سمت راست درخت تبديل کند .
با اين ابهامي که پیش مي آيد yacc ،انتقال را انتخاب مي کند .زيرا اين کار تقريباً همیشه کار درستي در برخورد با گرامرهاست .بايد
تلش کنید اين پیغامها را درك کنید تا مطمئن شويد که yaccتصمیم درستي گرفته است .اجرای yaccبا گزينة ، -Vيك فايل
پرحجم به نام y.out putتولید مي کند که به علت مشکل اشاره مي کند .
تمرين -5-8همانطور كه hoc 3بيان مي كند PI =3 ،ت ،قانوني است .آيا اين ايده ،ايده
خوبي است ؟ چگونه hoc 3را به منظور پيشگيري از نسبت دادن مقادير به ثوابت اصلح
مي كنيد ؟
y
است اضافه كنيد . x تمرين -6-8تابع داخلي a tan 2 y . x را كه زاويه اي را كه tanآن
تابع داخلي () randرا كه يك متغير تصادفي اعشاري براساس توزيع يكنواخت روي فاصله
(اوه) مي دهد را اضافه كنيدت .چگونه بايد گرامر را تغيير دهيد كه توابع داخلي با مقدار
متفاوتي از آرگومانها اجازه عمل دهيد ؟
تمرين -7-8چگونه يك قابلیت به منظور اجرای دستورات hocمشابه با ويژگي ساير برنامه های UNIXاضافه مي کنید ؟
تمرين -8-8کد را در math.cتصحیح کنید بطوريکه از جدول به جای يکسری از توابع يکساني که تولید کرديم استفاده کند .
از آنجا كه برنامهت hoc 3تاكنون بهت 5فايل وابسته است نه تنها يك فايل ،ت تفايلت make
پيچيده تر است .پيغام ΄΄ ΄΄vedvce/veduce conflictدر yaccحاكي از آن است كه به جاي
ل نشانه اي از يك خطاي واضح گرامري ديده مي شود . يك ابهام داخلي معمو ُ
266/322 محیط برنامه سازی لینوکس
خطـ YFLAGS=-dگزينهـ -dرا به خط دستورـ yaccکه باـ makeتولید شده مي افزايد ،اين گزينه بهـ yaccمي گويد که فايل
y.tab.hدستورات Idefineرا تولید کند .خط =OBJSاختصاری برای مفهومي که ساخته مي شود و به کرات استفاده خواهد شد ،
تعیین مي کند .ترکیب ،مشابه متغیرهای پوسته ای نیست؛ پرانتزها اجباری اند flag-1m .کتابخانه رياضي را نتیجه مي دهد که برای
تابعهای رياضي مورد جستجو قرار مي گیرد .
اكنونت hoc 3تبه فايلهاي four.oبستگي داردت .بعضي از ت o.فايلهاي بهت h.فايلها بستگي
دارند .با وجود اين وابستگي ها ،ت makeمي تواند نتيجه بگيرد كه چه كامپايل مجددي
بعد از اينكه تغييرات در هر يك از فايلهاي درگير صورت گرفت مورد نياز استت .اگر مي
خواهيد ببينيد كه makeبدون اينكه فرآيندها را اجرا كند چه انجام خواهد داد ،
$make-n
را امتحان کنید .
از طرف ديگر ،اگر بخواهید زمانهای فايل را به يك حالت پايا تحمیل کنید ،گزينه -)΄΄t)΄΄touchآنها را بدون انجام هیچ مرحله
کامپايل ،جديد ( )updateمي کند .
توجه کنید که ما نه تنها يکسری وابستگي به فايلهای منبع را اضافه کرده ايم ،بلکه برنامه های خدماتي متنوعي هم اضافه کرده ايم .
تمامي اينها در يك مکان به ترتیب قرار گرفته اند make .با پیش فرضش ،اولین چیزی را که در فايل لیست شده است مي سازد .اما
اگر يك مورد را به گونه ای نامگذاری کنید که وابستگي خاصي را نشان دهد ،مثل symbol.oيا make,prاول آنرا مي سازد .يك
تابعیت خالي به اين معني است که آن مورد هیچ گاه جديد نمي شود و تغییر تنها در صورتي رخ مي دهد که صريحا ً خواسته شود .
بنابراين
make prflpr $
نوع listرا که شما روی يك چاپ خطي خواسته ايد تولید مي کند ( .علمت @ در ΄΄@ ΄΄prاز انعکاس دستوری که توسط make
در حال اجراست جلوگیری مي کند .
و
267/322 محیط برنامه سازی لینوکس
انحرافي از lex
برنامه lexتحلیل گر واژه ای را که در يك رفتار مشابه با روشي که yaccتجزيه گر را تولید مي کند ،ايجاد مي کند .يك مشخصه
قوانین واژه ای زبانتان رامي نويسد و از عبارات منظم و قطعات ( fragements( cکه زماني که يك رشته منطبق شونده پیدا مي شود ،
مي کنید lex .آنرا به يك تشخیص دهنده ترجمه مي کند yacc,lex .با مکانیسم تحلیل گر واژه ای که اجرا مي شوند ،استفاده
قبل ً نوشته ايم همکاری مي کنند .در اينجا در مورد جزئیات ريز lexتوضیح نمي دهیم .بحث بعدی برای تشويق شما به آموختن
بیشتر است .برای اين منظور به راهنمای lexدر جلد 2Bراهنمای برنامه نويس UNIXمراجعه کنید .
در ابتدا در اين قسمت برنامه lexاي از فايلت lex .1ت آورده شده است .اين برنامه تابع
yylexرا كه تا بحال استفاده كرده ايم جايگزين مي كند .
هر قانون يك عبارت منظم شبيه آنهايي است كه درت egrepيات awkوجود داردت .با اين
تفاوت كهت ( escape,lexفرار -خروجت ) فضايت cشامل مثل ت n,tرا درك مي كندت .عمل در
براكت قرار ت ت ت ت مي گيردت .قوانين به ترتيب امتحان مي شوند و مفاهيمي نظيرت *و +تا
268/322 محیط برنامه سازی لینوکس
وقتي كه ممكن باشد بر يك ت رشته بند منطبق مي شوند .اگر قانون با بخش بعدي
ورودي منطبق شود ،عمل اجرا مي شودت .رشته ورودي كه انطباق نشان داده ،ت يك
رشته lexبه نام yylexقابل دسترسي است .
Makefileجهت استفاده از lexبايد تغییر کند :
مجددًا make ،مي داند كه چگونه يك فايل 1به فايل صفر دسترسي پيدا كند .تمام آنچه
كهت تازت تمات تمي تخواهد تاطلعات توابستگي تاستت ( .همچنين تبايدت تكتابخانهت lex 11ترات تبه
ليستي كه با CCجستجو مي شود اضافه كنيم .زيرا شناساگر توليد شده كامل نيست
ل اتوماتيك است :
) .خروجي جالب و كام ً
اگر تك فايل عوض شود make ،تك دستوره برای ساخت نسخه جديد ( )up to dataکافي است .
269/322 محیط برنامه سازی لینوکس
بحث کرده ايم که آيا با lexبه عنوان يك مورد جانبي عمل کنیم که خیلي مختصر نشان داده شده و سپس حذف شود .يا اينکه به
عنوان يك ابزار اولیه برای تحلیل واژه ای زماني که زبان پیچیده میشود .در هر دو مورد بحثهايي وجود دارد .مشکل اصلي ما ( Lex
گذشته از اينکه نیاز دارد کاربر زبان ديگری را نیز بیاموزد ) اين است که سرعت اجرای آن و تولید شناساگرهای بزرگتر و کوچکتر آن
نسبت به نسخه های مشابه Cکمتر استـ .همچنین در صورتي که يك مکانیسم ورودی به آن عملي غیرمعمول برایـ ، lexنظیر
بازگشت از خطا يا حتي ورودی از فايلها را دربربگیرد ،تطبیق اين مکانیسم برای lexنسبتا ً مشکلتر است .هیچ يك از اين موارد در
فضای hocجديدی نیست .مشکل اصلي محدوديت در فضاست .توضیح نسخه lexصفحات بیشتری نیاز دارد ،بنابراين (متأسفانه )
ما به Cبرای تحلیلهای واژه ای بعدی برمي گرديم .
تمرين -9-8سايزهاي دو نسخه hoc 3را مقايسه كنيد .راهنمايي :به size 1. 0مراجعه
كنيد .
Hoesرا كه مفسري براي يك زبان با جريان كنترل است ،در پيش داريم hoc 4 .يك مرحله
مياني است كه توابعي مشابه hoc 3فراهم مي كند .با اين تفاوت كه با چارچوب مفسر
hoesعمل مي كند .به اين دليل hoc 4را به اين گونه نوشته ايم كه دو برنامه يكسان
رفتار كنند .اين مسأله براي اشكال زدايي با ارزش است .همانطوري كه ورودي تجزيه
مي شود hoc 4 ،كدي را براي يك كامپيوتر ساده به جاي پاسخهاي محاسبه شده فوري
،توليد مي كند .هرگاه به آخر يك دستور مي رسد ،كد توليد شده تفسير مي شود تا
نتيجه مطلوب را محاسبه كند .اين كامپيوتر ساده يك ماشين پشته است .زماني كه به
يك كميت تحت عمل برخورد مي شود ،اين كميت به داخل يك پشته وارد ( )pushمي
شودت ( .صحيحتر اين است كه بگوييم كدي براي راندن اين كميت به داخل پشته توليد
مي شود )؛ بيشتر از اپراتورها روي مواردي كه در بالي پشته هستند عمل مي كنند .به
عنوان مثال براي بررسي رابطة
X=2*y
کد زير تولید میشود .
270/322 محیط برنامه سازی لینوکس
زماني که اين کد اجرا مي شود ،عبارت برآورد میشود و همانطور که در دستورات نشان داده شده ،نتیجه در xذخیره مي شودPop .
مي کند .ماشینهای پشته معمول ً مفسرهای ساده ای را نتیجه مي نهايي مقدار روی پشته را که ديگر مورد نیاز نیست از آن خارج
دهند ماشین ما هم استثناء نیست ـ آن تنها يك آرايه شامل اپراتورها و کمیتهای تحت عمل آنهاست .اپراتورها دستورات ماشین هستند
.هر يك فراخوان تابعي با آرگومانهايش (در صورت وجود) اند که دستورات را دنبال مي کنند .باقي کمیتهای تحت عمل ممکن است
همانند مثال بال از قبل روی پشته باشند .
كد جدول علمت براي hoc 4با كد جدول علمت hoc 3يكسان است .همچنين شروع در
init.cو توابع رياضي درت math.cيكسان استت .گرامر ،مشابهت hoc 3تاست اما عمليات
كاملً متفاوت است .هر عمل ،دستور ماشين و آرلگانهاي مرتبط با آنها را توليد مي كند
.به عنوان مثال سه مورد براي VARدر يك عبارت توليد مي شوند :يك دستور ، Varpush
اشاره گر جدول علمت براي متغير و يك دستور evalكه اشاره گر جدول علمت را بعد از
اجرا ،با مقاديرش جايگزين مي كند .كد براي ΄*΄ تنها mulاست ،چرا كه كميتهاي آن از
قبل روي پشته خواهند بود .
271/322 محیط برنامه سازی لینوکس
، Instنوع داده ای دستوری از ماشین است (اشاره گری به يك تابع که يك intبرمي گرداند ).که به زودی به آن برمي گرديم .توجه
کنید که آرلگانها ،اسامي توابعند ،يعني اشاره گرها به توابع يا مقادير ديگری که به اشاره گرهای تابع نسبت داده شده اند .
Mainرا تا حدی تغییر داده ايم .اکنون تجزيه گر پس از هر دستور يا عبارت برمي گردد .کدی را که تولید کرده اجرا مي شود .
Yyparseدر پايان فايل صفر را برمي گرداند .
272/322 محیط برنامه سازی لینوکس
تحليل گر واژه اي تفاوت كوچكي دارد .تفاوت اصلي اين است كه اعداد بايد از قبل
ذخيره شوند نه فوراً روش ساده تري در اين مورد ،نصب كردن آنهات (اعداد) در جدول در
كنار متغيرهاست .در اينجا بخش تغيير يافته yylexآورده شده است :
برنامه هاي مستقلي كه دستورات ماشين را اجرا و پشته را اداره مي كنند ،در
فايل جديدي به نام code.cنگهداري مي شوند .از آنجا كه اين فايل حدود 150خط است
مي آوريم : ،آنرا در قطعات مختلف
274/322 محیط برنامه سازی لینوکس
اجرا كردن ماشين ساده است .به دليل كوچكي برنامه مستقلي كه ماشين را يكبار
پس از نصب آن ،اجرا مي كند اجرا نسبتًا ساده است .
275/322 محیط برنامه سازی لینوکس
در هر سيكل شمارنده برنامه ( )PCبه دستور و دستور به تابع اشاره مي كند و آنرا
اجرات تمي تكندت .بدينت تترتيبت PCافزايش تمي تيابدت تتات تاينكهت تآمادهت تدستورت تبعدي تشودت .
دستوري ت تتباتتت opcode STOPرا ت تتخاتمه ت تتمي ت تتدهدتتت .بعضي ت تتاز ت تتدستورات ت ت،مثل
pc,varpush,constpushرا افزايش مي دهند تا به آرلگانهايي كه دستور را دنبال مي كنند
وارد شوند .
باقي ماشين ساده است .براي مثال ،عمليات حسابي در اصل مشابهند و با ويرايش
يك تك نمونه توليد مي شوند .در اينجا addآورده شده است .
مشكل ترين بخش طراحي bltinاست كه بيان مي كند كه * pcبايد به صورت اشاره
گره به تابعي كه يك مضاعف برمي گرداند و تابعي كه با d.valبه عنوان آرلگان اجرا مي
شود ريخته شود .
تشخيص ما در ، assign,evalدر صورتيكه همه چيز به درستي كار كند ،نبايد رخ دهد
.خطاهاي برنامه اي را كه سبب مي شوند پشته ،بسته شود ،توضيح نداده ايم .اگر
تغييري بدون دقت كافي ،در برنامه ايجاد كنيم ( كه امري معمول است ) ،بالسري در
زمان و فضا در مقايسه با فايدة شناسايي خطا كوچك است .قابليت Cدر اداره اشاره
گرها به توابع ،سبب ايجاد يكت كاد تكارآ و فشرده مي شودت .يك روش جايگزين براي
ساخت اپراتورها ،ثوابت و تركيب توابع معنايي به يك دستور گزينه اي ( )switchبزرگ در
277/322 محیط برنامه سازی لینوکس
حين اجزا ،تفسير وجود دارد كه روش ساده اي است و به عنوان تمرين پيشنهاد مي
شود .
΄ ΄-قبل ازت cmpبهت makeمي گويد كه عمل كند حتي اگرت ، cmpانجام نگيردت .اين
مورد به فرآيند اجازه عمل مي دهد ،حتي اگرت x.tab.hوجود نداشته باشدت ( .گزينهت -s
سبب مي شود cmpهيچ خروجي ايجاد نكند بلكه موقعيت خروج را تنظيم كند )
علمت ?$از قانون به listمواردي كه جديد نيستند وارد مي شود .متاسفانه ارتباط
تبديلت نمادين makeو تبديلت پوسته اي بسيار ضعيف است .
براي نشان دادن اينكه اين مورد چگونه عمل مي كند ،فرض كنيد همه چيز جديد (
)uptodataشده است .بنابراين
279/322 محیط برنامه سازی لینوکس
توجه كنيد كه هيچ چيز به جزء hoc.yمجدداً كامپايل نشده است .زيرا فايل y.tab.h
مشابه قبلي است .
تمرين )10-8سايزهاي پشته و pragرا ديناميك كنيد به طوريكه امكان دستيابي به
حافظه با فراخواني malloe.oوجود داشته باشد و hoc 4هيچ گاه خارج از فضا اجرا نشود
.
تمرين hoc 4 )11-8را به گونه اي اصلح كنيد كه به جاي توابع فراخواني از يك switch
روي نوع عمل استفاده كند .نسخه ها چگونه خطوط ،كد مرجع و سرعت اجرا را مقايسه
مي كنند ؟ سادگي ،نگهداري و رشد را چگونه مقايسه مي كنند ؟
گرامر پنج مورد shift/reduceرا مشابه آنچه در hoc 3مطرح شد ،دارد .
توجه كنيد كه اكنون دستوراتت stopدر مكانهاي مختلفي براي پايان دادن به تناوب
توليد مي شوند .مانند قبل ،ت pragpمكان دستور بعد از توليد WiJIاست WiJI .زماني
كه اين دستورات stopاجرا شوند ،حلقه در حال اجرا را خاتمه خواهد داد .با كمك يك
( subroutineزيرووالت ) كه از مكانهاي مختلفي فراخواني مي شود ،محصولي برايت end
ايجاد مي شود .اين subroutineيك Stopتوليد مي كند و مكان دستوراتي كه آنرا دنبال
مي كنند ،برمي گرداند .
كدي كه براي while، upتوليد شده به مطالعه خاصي نياز دارد .زماني كه به لغت
whileبرخورد مي شود ،عمليات whilecodeتوليد مي شود و موقعيت آن در ماشين به
281/322 محیط برنامه سازی لینوکس
مكانيت تدرت تماشينت تاستت تكه ت whileدرت تآنت تذخيرهت تميت تشودت .بنابراين $1
موقعيتت ifهم مشابهت whileاستت .با اين تفاوت كه درت ifسه موضعت else,thenو
دستوري كه پس از ifمي آيد ،حضور دارند .به زودي اين مورد را توضيح خواهيم داد .
اين بار آناليز واژه اي كمي طولني تر است ،بخصوص براي اينكه اپراتورهاي اضافي
در برمي گيرد . را
282/322 محیط برنامه سازی لینوکس
، Followيك كاراكتر را جستجو مي كند و اگر آنچه را كه يافته چيزي نباشد كه به
دنبالش بوده ،آنرا با ungetcروي ورودي عقب مي راند .
تعاريف تابعي بيشتري در hoc.hوجود دارد .ت به عنوان مثال ،تمامي رابطه ها ت به
ل مشابه hoc 4است .در اينجا خطوط پاياني آورده شده است :
جز اين مورد كام ً
بيشتر كدت Cنيز مشابه است ،هر چند تعداد زيادي از برنامه هاي مستقل جديد
براي اجراي اپراتورهاي رابطه اي وجود داردت .تابع ( Ieكوچكتر مساوي ) يك مثال نوعي
283/322 محیط برنامه سازی لینوکس
است :
دو برنامه مستقل كه خيلي واضح نيستند ،كدهاي if,whileمي باشند .نكته كليدي
در فهم اين موارد ،درك جريانهاي اجرايي در طي تناوبي از دستورات تا رسيدن به stop
است ،كه با رسيدن به آن برمي گردندت (از حلقه خارح مي شوندت ) توليد كد در طي
به طوريكه ، stopتناوبي از دستوراتي را كه فرآيند تجزيه با دقت طراحي شده است
بايد با تك فراخواني بررسي و اجرا شوند ،خاتمه دهد .بدنه يك whileو شرط آن و نيز
مي شوند تا آنچه را كه اجزاء else,thenيك دستور ifيا فراخوانيهاي بازگشتي اجرا
پس از تكميل عملياتشان به سطح برنامه كليت ( )parentبرمي گردانند ،ت اجرا شودت .
كنترل اين عمليات بازگشتي به وسيله كدي در if , whileانجام مي گيرد كه مستقيمًا با
دستورات if , whileدر ارتباط است .
مبحث قبلي را يادآوري مي كنيم .به دنبال عمل whileيك اشاره گر به بدنه حلقه ،يك
اشاره گر به دستور بعدي ،و سپس بخش آغازين شرط مي آيند .زماني كه whileخوانده
مي شود pc ،قبلً افزايش يافته است ،بنابراين به اشاره گر بدنه حلقه اشاره مي كند .
لذا pc+1به دستور pc+2به شرط اشاره مي كند .
284/322 محیط برنامه سازی لینوکس
كدت ifبسيار شبيه است .در اين مورد pcبه بخش thenاشاره مي كند ،ت pc+1به
else، pc+2به دستور و pc+3به شرط اشاره مي كند .
همچنين يك حلقه بيشتر در initبراي نصب واژه هاي كليدي نياز داريم :
تغييرات ~ 0براي اداره جدول علمت لزم است ؛كد Cكه هنگامي كه
اين تابع چاپ نيست كه اتوماتيك براي چاپ نتيجه نهايي يك برآورد ،فراخوانده مي
شودت .بلكه آن تابع ،تابعي است كه پشته را خالي مي كند و يك tabبه خروجي مي
افزايدت hoes .تا كنون يك ماشين حساب سرويس دهنده است ،هر چند براي برنامه
نويسي بزرگ و پيچيده قابليتهاي بيشتري لزم است تمرينهاي بعدي به بعضي از اين
قابليتها اشاره مي كنند .
تمرينت hoes )12-8رات به گونه اي اصلح كنيد كه ماشيني را كه در يك فرم قابل
خواندن جهت اشكال زدايي توليد مي كند ،چاپ كند .
تمرين )13-8اپراتورهاي رابطه اي مثل = ... ، * = +و اپراتورهاي افزايش و كاهش ++
- - ،را اضافه كنيد : : ، SS .را به گونه اي اصلح كنيد كه برآورد چپ به راست و پايان زرد
285/322 محیط برنامه سازی لینوکس
در ضمن اين مورد استفاده از فايلها را نيز نشان مي دهدت .نام فايلت ΄΄ ΄΄-ورودي
استاندارد راست .در اينجا يك تابع فاكتوريل آمده است .
به ارلگانها با يك تابع عملكرد مثل 1$و ...مراجعه مي شود .همانند آنچه در پوسته
وجود دارد .در ضمن نسبت دادن به آنها هم مجاز است .توابع و عملكردها بازگشتي
هستند اما تنها آرلگانها ت ت ت محلي اندت .ساير متغيرها كليت ( )globalمي باشند به اين
معني كه در كل برنامه قابل دسترسند .
Hoeتوابع را تاز عملكردها متمايز ت،ت زيرا با اين عمل تبه ايجاد سطح چك كننده با
ارزشي در توليد پشته منجر مي شودت .فراموش كردن يك بازگشت يا افزودن عبارت
اضافي و بي نظمي در پشته به سادگي ايجاد مي شود .
با تغييرات گرامري hoesبه hoc 6تبديل مي شود .اما اين تغييرات محلي اند .اكنون
نشانه ها و غيرپايانه ها مورد نيازند و %تعريف واحد عضو جديدي جهت نگهداري شماره
آرگومانها دارد :
287/322 محیط برنامه سازی لینوکس
288/322 محیط برنامه سازی لینوکس
محصولت براي arglistآرلگانها را مي شمارند .در نگاه اول ممكن است به نظر بيايد
كه لزم است آرلگانها متصل شوند ،اما در واقع لزم نيست ،زيرا هر exprدر ليست يك
آرلگان ،مقدارش را روي پشته در جايي كه دقيقاً خواسته شده قرار مي دهدت .تنها
دانستن اينكه چه مقدار روي پشته وجود دارد مورد نياز استت .قوانين برايت definيك
ويژگي جديد yaccرا كه عبارت از يك عمل ادغامي است ،معرفي مي كنند .قرار دادن يك
عمل در يك قانون امكانپذير است ،به طوريكه اين عمل در طي شناسايي قانون اجرا
شودت .آنت تويژگي ترات تدرت تثبت تاينت تحقيقت تكهت تدرت تيك تبيان تعملكردي تيات تتابعي تهستيم
استفاده مي كنيم .در روش ديگر توليد يك شبه علمت جديد براي شروع است كه در
زمان مناسب شناسايي شود ).در صورتيكه يك مفهوم خارج از بيان يك تابع يا عملكرد رخ
دهد ،در حاليكه نبايستي حادث مي شده ،تابع defonlyيك پيغامل خطا چاپ مي كند .
معمولً انتخابي براي اينكه آيا خطاها تركيبيت (قاعده ايت ) يافته شوند يا معنايي وجود
داردت .با يكي از اين موارد قبلً در اجراي متغيرهاي تعيين نشده مواجه شديمت .تابع
defonlyمثالي خوب براي مواردي است كه چك معايي ساده تر از چك تركيبي (قاعده اي
)است .
متغير indefدر hoc.yتعريف و توسط عملياتي براي defnتنظيم مي شود .تحليل گر
واژه اي با تستهايي براي آرلگانها ت يك $كه يك عدد بدنبالش مي آيد ت و براي رشته هاي
نقل شده ،افزايش مي يابدت .خطوط حاويت Backslashمثلت n/با يك تابعت backslashبه
مفسرها تفسير مي شوند .
289/322 محیط برنامه سازی لینوکس
يك تحليل گر واژه اي مثالي از يك ماشين محدود است چه در Cنوشته شده باشد
و چه با يك مولد برنامه مثل . lexنسخه adhoccما نسبتًا پيچيده شده است .براي بالي
ل lexهم در ساير كد منبع و هم جهت سادگي تغيير بهتر است .
اين سطح ،احتما ً
ساير تغييرات اغلب در كد Cايجاد مي شوند و با تعدادي افزايش در اسامي توابع به
hochبرده مي شوند .ماشين مانند قبل است ،به جز اينكه به آن ،يك پشته ثانويه جهت
رديابي تتابعت تعملكردت تتودرتوت تاضافهت تشدهت تاستت ( .استفادهت تازت تپشتهت تثانويهت تنسبت تبه
290/322 محیط برنامه سازی لینوکس
انباشتن انبوهي از اطلعات در يك پشته ساده تر است ).در اينجا شروع كد آورده شده
است :
از آنجا كه اكنون ،جدول علمت اشاره گرهايي به عملكردها و توابع و رشته هايي
براي چاپ را نگه مي دارد ،بخش به نوع واحد در hoc.hاضافه مي شود :
در طي كامپايل ،يك تابع به داخل جدول علمت با استفاده از defineوارد مي شود
291/322 محیط برنامه سازی لینوکس
defineاصلش را در جدول ذخيره مي كند و مكان آزاد بعدي را پس از كد توليد شده در
صورت موفقيت آميز بودن كامپايل جديد ( )updataمي كند .
تابع retآرلگانها را از پشته خارج مي كند ،اشاره گر چارچوب fpرا مجدداً ذخيره مي
كند و شمارنده برنامه را تنظيم مي كند .
293/322 محیط برنامه سازی لینوکس
برنامه هاي مفسر مختلف ،به كمترين جزئيات نياز دارند تا بتوانند در زماني كه در آن
بازگشت در يك عمل تودرتو رخ مي دهد موقعيت را پيش ببرند .اين عمل ،خيلي رسمي
نيست اما به طور مناسب با نشانه اي به نام بازگشت انجام مي گيرد كه زماني كه
عبارت بازگشتي صحيح است ،ديده مي شود .اگر بازگشت تنظيم شود while code , ،
if codeو اجراي زودهنگام خاتمه مي يابند call .آنرا به صفر برمي گرداند .
294/322 محیط برنامه سازی لینوکس
295/322 محیط برنامه سازی لینوکس
متغيرها يا تابعي به نام Varreadخوانده مي شوند .اگر end ---fileبرسد ،اين تابع
را برمي گرداند و متغير ويژه را تنظيم مي كند . 1 صفر را برمي گرداند .در غير اينصورت
اگرت end – fileدر فايل هاي ورودي موجود رخ دهد moreinput,varreadرا مي خواند
كه فايل آرلگان بعدي را در صورت وجود باز مي كند .ذكر آنچه ---moreinدر مورد فرآيند
ورودي نشان مي دهد در اينجا مناسب بنظر نمي رسد .جزئيات تكامل در پيوست 3آمده
است .اين بخش ما را به انتهاي طراحي hocمي رساند براي مقايسه در اينجا تعدادي
خط غيرخالي در هر نسخه آورده شده است :
296/322 محیط برنامه سازی لینوکس
)8-7برآورد عملكرد
Hocرا با برخي از ديگر برنامه هاي ماشين حساب UNIXمقايسه كرديم تا يك ايده
اوليه راجع به اينكه WEBچگونه عمل مي كند بدست آوريم .جدول زير بايد به عنوان يك
297/322 محیط برنامه سازی لینوکس
تخمين گرفته شود ،اما مي تواند نشان دهد كه روش ساخت ما ،يك روش منطقي است
بقاي زمانها بر حسب زمان كاربرد در روي يك PDP −11170محاسبه مي شوند .دو عمل
وجود داشت اولي محاسبةتابع ack 3,3آكرمن است .اين عمل تست خوبي از تابع CaB
مي باشد .اين تست به 2432خط نياز دارد كه برخي بسيار تودرتو هستند .تست دوم ،
محاسبه اعدادت فيبوناتچي تبا مقادير كمتر ازت 1000به تعداد صد دفعه استت .اين عمل
بيشتر عمليات حسابي را با يك فراخوان تابعي گاهي دربرمي گيرد.
چهار زبان عبارت بودند از ( bas , bc)1( , hacكه يك لهجه BASICقديمي است كه
تنها روي pop-IIاجرا مي كند ) و ( Cكه براي همه متغيرها از مضاعف استفاده مي كند)
اعداد جدول 1-8مجموع زمان CPUسيستم و كاربر مي باشند .
در ضمن فراهم آوردن امكان زمان سنجي براي يك برنامهت Cجهت تعيين اينكه هر
تابع چه مقدار از آن زمان را استفاده مي كند ،مقدور است .برنامه بايد مجدداً با بروز
نيمرخ ،با افزودن گزينهت -pبه هر كامپايل و فراخوانيت Cكامپايل شودت .اگرت makefileرا
اصلح كنيم تا عبارت زير را بخوانيم :
make clean; make CFLAGS=-p $
به طوريكه دستور Cمتغير CFLA5را استفاده كند و سپس بگوييم .
298/322 محیط برنامه سازی لینوکس
برنامه حاصله كد نيمرخ را در برخواهد گرفتت .زماني كه برنامه اجرا مي شود ،
فايلي به نامت mainخارج از داده ها را فراهم مي كندكه توسط برنامهت profتفسير مي
شود .
براي نمايش اين نمادها،به اختصار تستي روي hoc 6با برنامه فيبوناتچي بال انجام
داديم:
اندازه گيريهايي كه از نيمرخ بدست مي آيد ،تنها در حد نوسانات زماني استت .
بنابراين بايد با آنها به عنوان نشانگر استفاده شود نه داده هاي حقيقي ،اعداد در اينجا
پيشنهاد مي كنند كه چگونه hocرا در صورت نياز سريعتر بسازيم ،حدود يك سوم زمان
اجرا ،صرف وارد كردن و خارج كردن از پشته مي شود .در صورتيكه زمانهاي لزم براي
توابع اتصالت C Subroutineمثلت Cret , CSUرا هم در نظر بگيريم ،زمان سرآمد بيشتر
خواهد بودت .و me auntقطعه اي از كد نيمرخ است كه بات CC-Pكامپايل مي شودت ) .
جايگزين كردن فراخوانهاي تابع با ماكروها بايد تفاوت چشمگيري ايجاد كند .
جهت بررسي اين موضوع كد Cرا اصلح كرديم .به اين صورت كه فراخوانها با ورود و
خروج ( )popm , pushرا با ماكروها براي اداره پشته جايگزين كرديم .
299/322 محیط برنامه سازی لینوکس
(تابع popبه عنوان يك opcodeدر ماشين مورد نياز stmاست .بنابراين نمي توانيم
تمامي popها را جايگزين كنيم ).نسخه جديد حدود 35%سريعتر اجرا مي شود .زمانها
در جدول 1-8از 5/5به 3/7ثانيه و از 5به 3ثانيه كاهش مي يابند .
تمرينت )22-8ماكروهايت pop , pushخطاها را چك نمي كنندت .دستوري جهت اين
عمل توليد كنيد چگونه مي توانيد چك كردن خطا با نسخه هاي تابعي را با سرعت
ماكروها تلفيق كنيد ؟
8-8-نگاهي به عقب
دروس مهمي در اين فصل وجود دارندت .اول اينكه ابزارهاي طراحي زبان امكانات
مهمي هستندت .اين ابزارها ،امكان تمركز روي بخش جذاب كار – طراحي زبان – را
فراهم مي كنند .زيرا تجربه اين كار ساده است .همچنين استفاده از يك گرامر ،ساختار
سازمانت تدهنده تايت ترات تبرايت تپيادهت تسازي تفراهمت ت تمي تكندت تتت تاينت تساختارت تبرنامهت تهاي
مستقلي است كه به وسيله گرامر به هم مرتبط مي شوند و به موازات پيشروي تجزيه
در زمانهاي مناسب فراخواني مي شوند .
نكته دوم كه منطقي تر هم است ،ارزش فكر كردن به كاري كه در دست داريم
بيشتر به عنوان طراحي زبان است تا به عنوان نوشتن برنامه .سازماندهي يك برنامه به
عنوان يك زبان منظم ،تركيبي ت ( كه رابط كاربر است ) را ايجاد مي كند و ساخت مرا
ساخت را ساختار مي بخشد .همچنين به حصول اطمينان از اينكه ويژگي جديد تا حدي
با ويژگيهاي قبلي انطباق نشان مي دهد ،كمك مي كندت .زبانها مطمئناً به زبانهاي
برنامهت تتنويسيت تتمرسومت تتمحدودت تتنميت تتشوندت تتت ت تتنمونهت تتهاييت تتاز ت تتتجربهت تتخودمان
lex,yacc,pic,eqnو makeمي باشند .
همچنين آموزشهايي جهت نحوه استفاده از ابزارهاي موجود وجود دارد .به عنوان
مثال ,makeخيلي كارآ نيست .اين برنامه خطاهايي را كه به سبب فراموشي در كامپايل
مجدد بعضي برنامه هاي مستقل به وجود مي آيد ،حذف مي كند .اين مقوله (كامپايل
مجدد) اطمينان مي دهد كه هيچ كار اضافي انجام نشده است و روش مناسبي جهت
گروهبندي اپراتورهاي مرتبط و شايد وابسته در يك تك فايل فراهم مي آورد .
300/322 محیط برنامه سازی لینوکس
فايلهاي سرآمد روش خوبي براي اداره تعريف داده هايي كه بايد در بيش از يك فايل
حضور يابند ،هستند .با مركزيت بخشيدن به اطلعات ،آنها خطاهايي را كه با سخنهاي
ناپايا ايجاد مي شوند ،بخصوص زماني كه بات makeكوپل مي شوند ،حذف مي كنندت .
همچنين سازماندهي داده ها و برنامه هاي مستقل به داخل فايلها مهم است به گونه
اي كه زماني كه وجود آنها ضروري نيست قابل ديدن نباشند .
دوت تموضوع توجود تدارد تكهت تبهت تدليل تكمبودت تفضات تبرت تآنهات تتمركز تنكرديمت .يكي تميزان
استفاده از ساير ابزارهاي UNIXدر طي طراحي است كه در خانواده hocانجام داديم .
هر نسخه برنامه ،در يك دايركتوري جداگانه به همراه فايلهاي يكه اي كه به يكديگر متصل
شده اند مي باشد Dr , Is .به كرات جهت رديابي استفاده شدند .بسياري از پرسشهاي
ديگر با برنامه ها پاسخ داده مي شوند .به عنوان مثال اينكه يك متغير خاص كجا معرفي
مي شود .از grepاستفاده كنيد .در اين نسخه چه تغييري ايجاد كرديم ؟ diffرا به كار
ببريدت .چگونه تغييرات را در يك نسخه جمع كرديم ؟ ازت idffاستفاده كنيدت .اندازه فايل
چقدر است ؟ از weاستفاده كنيد .آيا زمان براي ساخت يك كپي مناسب است ؟ از .ep
استفاده كنيد .چگونه مي توان تنها فايلهايي را كه نسبت به كپي قبلي تغيير كرده اند ،
كپي كرد ؟ت makeرا به كار ببريدت .اين روش كلي ،روش نوعي توسعه روزافزون برنامه
روي سيستمت UNIXاستت .ميزباني براي ابزارهاي كوچك كه به صورت مجزا و يا در
صورت نياز تلفيقي استفاده مي شوند ،به مكانيزه كردن كاري كمك مي كند كه در غياب
اين ميزبان مجبور بوديم با دست انجام دهيم .
تاریخچه و معرفي کتاب
Yaccتوسط Steve Johusonطراحي شد .از نظر فني ،گروهي از زبانهايي كه yacc
براي آنها مي تواند تجزيه گر ايجاد كند ( LALR)1ناميده مي شوند :كه يك تجزيه چپ به
راست بوده و به جستجوي حداكثر يك نشانه در ورودي مي پردازد .مفاد يك بيان مجزا
جهت رفع اولويت و ابهام در گرامر براي yaccجديد است .به ΄΄ تجزيه تعييني گرامرهاي
مبهم΄΄ نوشته ، A.V.Aho,CACM,J.D.U//man,S.C,Johnsonآگوست 1975مراجعه كنيد .
همچنين براي توليد و ذخيره سازي جداول تجزيه تعدادي الگوريتم و ساختارهاي داده اي
جديد وجود دارد.
بيان خوبي از تئوري پايه اي قابل توسعه yaccو ساير مولدان تجزيه ممكن است .در
اصول طراحي كامپايل نوشته ( Addsiam-wesly( J.D.Ullman,A.V.Aho 1997يافت شود .
خودت yaccدرت تجلدت 2راهنمايت تبرنامهت تنويست UNIXتوضيحت تدادهت تشدهت تاستت .اينت تجلد
301/322 محیط برنامه سازی لینوکس
ماشين حسابي قابل مقايسه با hoc 2را نيز ارائه مي دهد .ممكن است اين مقايسه
آموزنده به نظر بيايد .
Lexدرت تاصلت تتوسطت mike leskنوشتهت تشدت .تئوريت lexنيزت تتوسطت Ullman , Aho
توضيح داده شده و خود زبان lexدر راهنماي برنامه نويس UNIXآمده است yacc .وتا
حد كمتري lexجهت ساخت بسياري از پردازشگرهاي زبان مثل كامپايلر Cقابل انتقال ،
پاسگال ،فورترن VV,Ratfor,awk,be,eqn,picاستفاده شده اند .
Makeتوسط stu Feldmanنوشته شد به : MAKEبرنامه اي براي حفظ برنامه هاي
كامپيوتري ،نرم افزار ت تمرين و تجزيه ،آوريلت 1979مراجعه كنيدت .برنامه هاي كارآي
نوشتاري نوشته ( prentice-Hall( John Bentley,1982تكنيكهايي را براي سرعت بخشيدن
به برنامه ها توضيح مي دهند .اولين تاكيد بر يافتن الگوريتم راست و سپس يافتن مجدد
كه در صورت لزوم است .
302/322 محیط برنامه سازی لینوکس
چیزی خواسته شده است را آسان ميکند .هر گدام از اينها بايك برنامه مجزا استفاده ميشود که زبانش را به فرمان troffبر ميگرداند
ترجمه ميکند.برنامهها وتوسط مسیرهای اطلعاتي ( )pipesمنتقل ميشوند.
اين پیش پردازندهها نمونه خوبي از رهیافت UNIXبه عرصه کار است .نسبت به ساخت
troffحتي بزرگتر و پیچیدهتر از چیزی هست .برنامههای مجزا نیز با آن همکاری ميکنند(.البته ابزارهای توسعه زبان که در فصل 8
توضیح داده شده برای کمك به تحقیق سازی مورداستفاده قرار گرفته است).
ما دو برنامه را برايتان شرح خواهیم داد .اول tblکه جدولها را فرمت ميکند و دوم eqnکهعبارات رياضي را فرمت ميکند.
ما سعي ميکنیم در مورد آماده سازی فايلها و تامین ابزارها توصیه هايي داشته باشیم نمونههايي که در سراسر اين بخش بیان شد
فايلي ست که زبان nocو صفحات راهنمای nocراتوضیح خواهد داد .اين فايل در صفحه 2چاپ شده است.
يك فايل توسط ماژههای قسمتهای اصلي در بستههای ماکرو توضیح داده خواهد شد(.عنوان) سر بخشها ،پاراگرافها) و نه با
جزئیاتي فاصله گذاری ،فونت و سايز در يك برنامه.اين روش شما را از انجام کاری سخت نجات ميبخشد و از فايل شما در برابر
جزئیاتنامربوطه محافظت ميکند .در حقیقت با استفاده از تعاريف مختلف دستگاه ماکرو -با اساميمنطقي مشابه -شما ميتوانید فايل
را با اندکي تفاوت جلوه گر سازيد .برای مثال يك فايلممکن است مراحل يك گزارش تکنیکي کنفرانس نشريه و يا کتاب را به وسیله
فرمانهایفرمت کننده بگذارند ،که اين عملیات با چهار بسته ماکروی مختلف انجام ميشود .
ورود به troffکه آيا يك بسته ماکروا را شامل ميشود يا نه ،يك متن معمولي ست که با فرمانهایفرمت شده پديد ميآيد .دو نوع
فرمان وجود دارد .اولي يك دورهای را در ابتدای خط شاملميشود ،که با يك يا دو حرف و يا رقم همراه است و شايد هم يك پارامتر
همانگونه که در زيرنشان داده شده است.
pp
ft B this is a little font paragraph
troffکه در فرمان به صورت پیش ساخته وجود دارد ،با حروف کوچك نامگذاری ميشود .درصورتیکه فرمانها در بستههای ماکرو با
حروف بزرگ نام برده ميشوند .برای مثال ppيكفرمان msبرای پاراگراف و ft Bيك فرمان troffاست که در فونت درشت تغییر
ايجاد ميکند(فونتها با حروف بزرگ نامگذاری ميشوند و ممکن است در حروف چینهای مختلف،متفاوت باشند)
دومین فرم فرمان troffتوالي کارکترهاست ،که با يك اسلش شروع ميشود و ممکن است در هرجايي از ورودی ظاهر شود .برای مثال
FBتغییری در فونت درشت به وجود ميآورد به اينشکل از فرمان يك troffکامل ميگويند.
شما ميتوانید با اندکي توجه فرمان ppرا قبل از هر پاراگراف فرمت کنید و برای بسیاری ازفايلها ميتوانید فرمانهای msمتفاوت 12
تايي را به خوبي به انجام برسانید .برای مثالضمیمه 2را nocرا توضیح داده دارای يك عنوان اسامي نويسندگان ،چکیده نامه ،عنوان
هاييکه شماره بندی شده و پاگرارف ميباشد و تنها دارای 14فرمان مجزاست که تعدادی از انها بهصورت جفت آمده است .متن اين
فرمهای معمولي را از msبرداشت ميکنیم.
TL
(title of document )oneor mor lines
au
304/322 محیط برنامه سازی لینوکس
نمايشگر:
گرچه اينکه troffرفتن را پر کند و يا همستون سازد بسیار مطلوب است اما بعضي اوقات نیزناخوشايند به نظر ميرسد .برای مثال
برنامهها نبايد حاشیه خود را همستون سازند .يك چنینموارد فرمت نشده را متن نمايشگر ميخوانند .فرمانهایـ DE)display
End ( , DC)display start(msاز اينکه متن مطابق با ظاهرش چاپ شود جلوگیری ميکنند و آنم را بهصورت مرتب حاشیه بندی
ميکند .در اينجا قسمت بعدی يك راهنمای nocنشان داده شدهکه شامل يك نمايشگر کوچك است.
nocيك زبان گوياست مانندـ cگرچه تعداد زيادی عبارات روند کنترل وجود دارد .بسیاری ازعبارات مانند نسبت دهي مورد بي
توجهي قرار ميگیرند برای مثال اپراتور نسبت دهي =-میزان عملوند راست را به عملوند چپ نسبت ميدهد .و میزانش را به دست
ميآورد .نسبتدهيهای چندگانه بدين ترتیب کار ميکنند .گرامر عبارت اين چنین است:
en pr
number
va riable
enpr
enpr binop enpr
unop enpr
functron cagnments
داخل متن يك نمايشگر به صورت نرمال پر شده و يا همستون شده نیست .علوه بر اين اگر درمتن موجود جای خالي کافي وجود
ندارد مطالب نمايش داده شده به صفحه بعذدی انتقالمييابدDS .انتخابها بسیاری را شامل ميشود .مثل ً Lبرای همستوني سمت
چپC ،که هرسطر را به طور انحصاری در مرکز قرار ميدهد ،و Bکه کل نمايشگر را در مرکز قرار ميدهد.
آيتمها در نمايشگر بال با تبها جدا ميشوند .تبهای troffدر نیم اينچي يکديگر قرارميگیرند .و نه در فاصله هشت تايي که رايج
بوده حتي اگر تب متوقف شود هر فاصله هشتتايي وجود دارد گرچه کارکترها عرضهای متفاوتي دارند .تبهای پردازش شده
توسطtroffآنگونه که انتظار ميرود ظاهر نميشود.
تغييرات فونت
ماکروهای msسه فرمان برای تغییر فونت فراهم ميکنندR .فونتها را به لتین تغییر ميدهد کهيك فونت معمولي و رايج استI.آن را
به ايتالیك تغییر ميدهد و Bآن را سیاه ميکند هر فرمانفونت را برای متن بعدی گزينش ميکند.
this taxt is roman,but
I
this text is italic
R
This is roman agcin, and
B
this is blod fale
Iو Bيك نشانه انتخاب کردهاند که در اين حالت تغییر فونت فقط در مورد نشانهها اعمالميشود .در troffنشانهها شامل فضاهای
خالیست که نقل قول شدهاند گرچه کارکترهای نقلقول کننده نقل قول مضاعف هستند .
در نهايت دومین نشانه برای Iو يا Bکه به صورت لتین چاپ ميشود بدون فضای خالي بهنشانه اول ضمیمه ميشود .اين صورت به
میزان وافری برای نقطه گذاری در فونت سمتراست استفاده ميشود .اين جمله را ( parenthetical. I italic wordsکه به عنوان
parenthetical italice wordsنادرست چاپ شده با اين جمله ()parenthetical i italic wordکه به عنوان parenthetical italic
wordsدرست چاپ شده مقايسه کنید.
306/322 محیط برنامه سازی لینوکس
تفکیك فونتها توسطtroffتشخیص داده ميشود ولي نتیجه مطلوبي ندارد .بر رویکارکترهای ايتالیك تاکید زيادی شده و کارکترهايي
با فونت درشت وجود ندارد اگر چه بعضيشکلهایـ nroffحروف درشت را توسط روی هم چاپ کردن کارکترها شبیه سازی
ميکند.
فرمانهاي متفرقه :
پا نوشت توسط FSمعرفي شده و با FEپايان مييابد .شما مسئول هر علمت تشخیص هويتيشبیه يك نماد ستاره و يا نماد خنجر در
پا نوشت اينگونه ساخته ميشود.
idetifying nerk like an asterisk or a dagger.
fs
dg like this one.
FE
this foot note was creat ea with
پاراگرافهای فاصله دار با يك شماره و يا علمت ديگری در حاشیه با فرمانIPساخته ميشود.برای ساختن آن اولین پاراگراف
کوچك - 2 .دومین پاراگراف که ما ان را طولني ترساختیمبرای اينکه نشان دهیم که بر روی سطر دوم به مانند سطر اول فاصله دار
ميشود.
IP
first little paragtaph
IP
SECOND PARAGRAPH...
خاتمه ميدهند .نشانه IP,)LEFT-INSTIFIED PARYRAPH,.PP
IPمي تواند هر رشته -متني()Stringباشد .در صورت نیاز از گیومه برای حفاظت از فضاهایخالي استفاده کنید .نشانه دومي ميتواند
برای تعیین کردن بسیاری از فواصل استفاده ميشود.
فرمانهای .KSو KEبا يکديگر نگه داشته ميشوند .متن که بین اين دو فرمان محصور شده اگردر صفحه موجود جانگیرد به صفحه
اول جا دهیم ميتوانیم ازـ KFبه جایKSاستفاده کردهتامتن مورد نظر در بالی صفحه بعدی قرار گیرد .ما ازـ KFبرای تمامي
جدولهای اين کتاباستفاده کردهايم.
شما ميتوانید مقادير پیش ساختهmsرا تغییر دهید با قرار دادن ثبات اعداد که متغیرهایtroffهستند و مورد استفاده msبوده است .و
شايد اينکه ثباتها اندازههای متن و فواصل بینسطرها را کنترل کند رايجتر باشد .اندازه متن نرمال 10پونت است که هر پونت تقريباً
1/72اينچ است .سطرها به طور نرمال در مکانهایـ 12پونتي قرار ميگیرند برای تغییر آن برای مثالبهـ 9و 11ثبات اعداد را در
vs,psقرار بده.
ثبات اعداد ما شامل LLبرای طول سطرستPI ،برای فاصله پاراگراف و PDبرای تفکیك بینسطرها ،که تمامي اين عملیات در PPو يا
LPبعدی تاثیر گذار است.
307/322 محیط برنامه سازی لینوکس
ما در اينجا به جزئیات بستههای ماکرویـ mmنخواهیم پرداخت که البته در برخي جزئیاتشبیهmsمي باشد و همانندـ msبر روی
پارامترها کنترل دارد البته با توانايي بیشتر و پیاتمخطانمای بهتر .جدول 9-2فرمانهای mmرا در مقابل با فرمانهای msدر جدول 9-1
نشانميدهد.
سطح troff
در يك عمر حقیقي هر چیزی بايد به مهارتهای msو mmو يا وابستههای ديگر واقف باشد .وبهقابلیتهای تروف ( )troffخالي
دست يابد ،که اجرا شدنش شبیه به برنامه ريزی در زبانهمگذاری اسمبلي است گرچه به صورت هشدار دهنده اجرا ميشود.
سه موقعیت روی ميدهد .دستیابي به کارکترهای ويژه سايز خطي و تغییرات فونت وعملکردهای فرمت کننده اصلي.
نامهاي كاركترها :
کارکترهای ناآشنا -حروف يوناني مثل گرافیکي و سطرها و مکانهای متفاوت و متنوع آسانهستند ،اما خیلي هم روشنمند و منظم
نیستند .يك چنین کارکترهايي دارای نامي هستند مثلcدر جايي که cيك کارکتر تنهاست و يا cdموقعي که cdيك کارکتر جفتي است.
troffيك علمت منهایـ ascllرا به عنوان خط تیرهـ ( )hyphanبه جای اينکه يکگ منها چاپميکند .يك علمت منهای درست
اينگونه تايپ ميشود .و علمت دش بايد اينگونه چاپشود.ه به جای کارکتر آمده است .جدول 9-3برخي از کارکتر ويژه رايج و
معمولي را لیست کردهاست ،که در راهنمایtroffبیش از اين لیست کارکتر وجود دارد که اين لیست با سیستم شما ممکناست متفاوت
باشد .مواقعي برای تغییر رايجترين کارکتر خود کار ماشیني است .توالي و ترتیببرای چاپ يك اسلش تضمین شده است و در
خروجي برای يك اسلش استفاده ميشود .بهعبارت ديگر فضايي با عرض صفر است .بیشترين کاربرد آن جلوگیری troffاز تفسیر
تناوبها درآغاز سطر است.
ما در اين سطر از زياد استفاده کردهايم .برای مثال کل msرا در آغاز اين فصل اينگونه تايپ شده.
tl
title if document
Au
Author name
AB
البته قسمت بال نیز اينگونه تايپ شده.
tl
i title of document
au
و شما ميتوانید تصور کنید که چگونه به ترتیب و به نوبت تايپ شده است.
308/322 محیط برنامه سازی لینوکس
جدول 9-2
فرمانهای فرمت کننده mm
چکیده را آغاز کنید که با aeپايان ميپذيردAS .
اسم نويسنده به عنوان اولین نشانهAU
متن را با حروف پر رنگ آغاز کنیو يا نشانهها را پر رنگ کنید B
متن را کنار هم بگذاريد و در صورت لزوم در صفحه بعدی شناور کنید DF
متن نمايشگر را آغاز کنید که با DEپايان ميگیردDS.
معادله را آغاز کنید ورودی eqnکه با ENپايان ميگیردEQ.
پا نوشت را آغاز کنید که با FEخاتمه مييابد FS
متن ايتالیك را شروع کنید و يا نشانهها را ايتالیك کنید I
سطح th-nعنوان شماره گذاری شده H
عنوان شماره گذاری نشده HU
پاراگراف از nr pt 1برای پاراگرافهای فاصله دار استفاده ميشود P
برگشت به فونت لتین R
عنوان به دنبال فرمان mmبعدی ميآيد TL
جدول را شروع کنید (ورودی ()tbکه با TEخاتمه ميپذيردTS.
کارکتر خاص ديگری که گاهي رخ ميدهد ،فاصله غیر قابل بسط است يك به دنبال فاصله و ياجای خالي ميآيد .نرمال troffيك
فاصله را برای همستون سازی حاشیهها بسط ميدهد .اما يكفاصله غیر قابل بسط هرگز همستون نميشود .اين شبیه هر کارکتر
ديگريست که عرض مشخصيدارد و ميتواند برای پذيرفتن واژههای چند گانه به عنوان يك نشانه تنها به کار رود.
i title /of/docn ment
309/322 محیط برنامه سازی لینوکس
جدول 9-3
troffبرخي مراتب کارکتر خاص
--خط تیره
\hyخط تیره ،مانند بال
\-علمت منها در فونت موجود
em dash\cem
&\ حفاظت از تناوب پیشین
\blankفاصله غیر قابل بسط
\کارکتر نموی خروجي
\eگلوله
\)bnخنجر
\)bg
\)*a
x*\)fتغییر به فونت
xx\fxxتغییر به فونت
n=o\snقبلي n،تغییر به سايز پونت
\s+-nتغییر اندازه پونت نسبي
بسیاری از تغییرات فرمت و فونت ميتواند در ماکروهای ابتدای خط ايجاد شود .شبیه .Iوليبعضي اوقات تغییرات به صورت خطي و
رديفي ساخته ميشوند .کارکتر خط جديد يك تفکیكکننده کلمه است .چنانچه يك فونت در وسط کلمه تغییر مييابد ماکروها غیر
قابل استفادههستند .زير بخشها در اين مورد بحث ميکند که چگونهـ troffبر اين مشکل غلیه ميکند .توجهداشته باشید که اين
troffاست که از مهارتها و قابلیتها حمايت ميکند و نه بستههایماکروی.ms
troffاز کارکترهای يك اسلش برای معرفي فرمانهای خطي استفاده ميکند f .فرماني برای تغییرفونت و \ sفرماني برای تغییر اندازه
پونت بسیار رايج است.
فونت توسط\ fبا يك کارکتر به سرعت بعد از fمشخص می شوة.
a\fbf riv\fiolous\fr\fivar\fbiety\fr
of\fifonta\fp
متغیر فونت \fpبه فونت قبلي باز ميگردد -به هر صورتي که فونت قبل از آخرين تغییر بوده است -بسیاری از فونتها دارای 2نام
کارکتر هستند ،که توسط فرمت \f)xxجايي که xxنم فونتميباشد مشخص ميشوند .برای مثال فونتي که روی حروفچین ما جايي که
برنامههای اين کتابچاپ شده cwخوانده ميشود بنابراين keywordاينگونه نوشته ميشود.
310/322 محیط برنامه سازی لینوکس
\f)cw keyword\fp
که البته تايپ کردن آن بسیار ملل آور است .بنابراين ماکرو يکي از مصداق های
msوـ mmاست که ما ديگر نبايد back slashرا بخوانیم و يا تايپ کنیم .ما برای حروفچینيواژههای خطي از اين روش استفاده
ميکنیم مانند troffبرای مثال:
the
cw troff
for matter
تصمیمات فرمت کننده که توسط ماکروهای تعريف ميشود برای تغییرات بعدی بسیار سادهاست .تغییر سايز توسط مراتب \snمعرفي
ميشود جايي که nيك يا دو ورقعي است و سايزجديد را مشخص ميکندs8\ .به هشت نوع پونت تغییر مييابد .تغییرات نسبي ممکن
استتوسط علمت منفي و يا مثبت در مقابل سايز ساخته شود .برای مثال کلمه ميتواند به شکلحروف کوچك چاپ شود.
\s-25mall caps\so
soباعث ميشود که سايز میزان قبلي خود باز گردد .اين قايسي ست از
\fpالبته به رسم troffبه صورت \spبیان نميشود .مصداق msدر نظر ما يك ماکروی با حروفبزرگ ())uc)upper caseبرای کار.
با يك بسته ماکروی خوب شما بايد مقداری از فرمانهایtroffرا بدانید برای کنترل فضای خالي ويا پر کردن و قرار دادن تب و غیره
فرمان brباعث يك انقطاع شکست ميشود که ورودی بعدی بههمراه .brبر روی خط خروجي جديد خواهد شد .که اين ميتوانست
برای مثال برای دو قسمتيکردن عنوانهای بلند بر روی مکاني خاص استفاده شود.
فرمان nfپر کردن سطرهای خروجي را قطع ميکند .هر سطر ورودی مستقیم به سوی يك ازسیطرهي خروجي ميرود .فرمان fiپر
کردن از عقب را قطع ميکند .فرمانceسطر بعدی را درمرکز قرار ميدهد.
فرمان bpيك صفحه جديد را آغاز ميکند .فرمان spباعث ميشود که تنها يك سطر خالي درخروجي ظاهر شود .يك فرمان spمي
تواند با يك نشانه همراه باشد تا مشخص کند چند سطرخالي و چند فضای خالي نیاز است.
رمان بال جايگاههای تب را در فواصل معیني از حاشیه چپ مشخص ميکند با \
spهر شمارهای در هر اينچ قرار دارد اگر با همراه باشد جايگاه تب که توسط rافزوده شده متن رادر جايگاه تب بعدی همستون ميکند.
311/322 محیط برنامه سازی لینوکس
وقتي که ماکرو راه اندازی ميشود \n$میزان نشانه n=tnرا تهیه ميکند و اگر نشانه n-tnفراهمنشد خالي ميماند .يك اسلش دو تايي
در ارزيابي \nدر مدت تعريف ماکرو تاخیر ايجاد ميکند.از اينکه نشانه به عنوان يك فرمان troffتفسیر شود جلوگیری ميکند پیش
پردازندههای tbl,eqn
troffيك برنامه پیچیده و بزرگ است چه در ورودی و چه در خروجي بنابراني تغییر دادن آن برایقبول يك کار جديد به سادگي
صورت نميگیرد .طبق توسعه برنامهها برای رياضیات و جدولهاکه رهیافت متفاوتي دارند و طرح ريزی زبانهای مجزا که توسط
برنامههای مجزا تحقیق مييابد،به عنوان يك پیش پردازنده برای troffعمل ميکند در حقیقت troffيك زبان همگذتاری اسمبلياست
برای يك ماشین حروفچیني و به آن برگردانده مترجمه ميشوند.
اول eqnبه وجود آمد .آن اولین کاربرد yaccبرای يك زبان برنامه ريزی نشد بودtbl .بعد ازآنآمد که شبیه به eqnبود ،البته با يك نحو
نا مربوطه و غیر وابسته.
از yaccاستفاده نميکند زيرا گرامرش بسیار ساده است.
مسیر برنامههای مجزائي تقسیم ميشود گذشته از فاکتورگیری کار به چند بخش مسیرهایاطلعاتي ارتباط بین بخشها و برنامهها را
کاهش ميدهند .اين پونت آخری مهم است و نیازی بهدستیابي به کد منبع برای ساخت پیش پردازندهها ندارد .علوه بر اين باو وجود
مسیرها هیچ فايلبزرگي که ايجاد ناراحتي کند وجود ندارد و گرنه موارد تشکیل دهنده عاملها برای خط زدائي بهصورت مجزا اجرا
ميشوند.
وقتي که برنامههای مجزا با مسیرها ارتباط برقرار کنند مشکلي به وجود ميآيد و تا وقتي کهورودی و خروجيهای زيادی وجود دارد
سرعت کمي دچار اختلل ميشودtbl .و eqnيك بسطدهي 8به 1از ورودی به خروجي ايجاد ميکنند .از همه مهمتر اطلعات تنها
يك مسیر را دنبالميکنند .برای مثالeqn ،مي تواند سايز پونت موجود را تعیین کند .که منجر به زشتي زبانميشود .در نهايت گزارش
دادن خطا در اينجا سخت ميشود .استفاده از تفکسكها خطاها راسنگینتر نشان ميدهد .بنابراني بیشتر پیش پردازندهها ديگر که
نوشته شدهاند دارای طرح ومدل يکساني هستند.
بگذاريد بحث مختصری در مورد tblداشتعه باشیم .اولین چیزی که ما ميخواهیم نشان دهیمجدول اپراتورها از فايل hocميباشد.
tblفايل ورودی خود را و يا ورودی استاندارد راميخواند و متنها بین فايلهای .)ts)table startو )TE)Table endرا تبديل ميکند.
312/322 محیط برنامه سازی لینوکس
بهفرمان troffکه جدول را چاپ ميکند .ستون را مرتب ميکند و از تمامي جزئیات چاپي مراقبتميکند .سطرهای TS.TEکپي شده
هستند بنابراين يك بسته کاکرو ميتواند تعاريف مناسبي برایآنها فراهم کند .برای مثال ادامه جدول روی يك صفحه و تنظیم آن در
محیط متن.
گرچه نیازی است که به يك راهنمای tblبرای ساختن جدولهای پیچیده نگاهي بیندازيد .يكمثال برای نشان دادن شکلهای معمولي
و رايج آن کافیست .در اينجا مثالي از فايل nocوجوددارد.
کلماتي که قبل از سعي کالن ()center,boxقرار دارند خواص جدول را توضیح ميدهند يعني آنرا در وسط جدول به طور افقي قرار
ميدهد و يك مستطیل دور ان ميکشد .ديگر امکانات آنشامل (all box daubleboxکه هر کدام موارد داخل مستطیل است) و
expandجدول را بهعرض صفحه بسط ميدهد ميشود.
سطرهای بعدی فرمتهای بخش بعدی جدول را توضیح ميدهد که در اين حالت سطر عنوان وقسمت اصلي جدول قرار دارد .اولین
تشريح برای سطر اول جدول است .دومین تشريح برایسطر دوم کاربرد دارد .و آخرين کاربرد برای سطرهای باقي مانده است در
جدول 1تنها و سطرتشريح وجود دارد بنابراين دومین تشريح برای هر سطر جدول به جز سطر اول کاربرد دارد .کارکترفرمت برای
مواردی که در وسط ستون قرار دارد cاستr .و tبرای همستون بازی است راست وچپ و nبرای همستون سازی عددی بر روی پونت
ده دهيs .يك ستون گسترده شده را مشخصميکند .در اين حالت csيعني قرار دادن در وسط جدول توسط گسترده کردن ستون دوم
313/322 محیط برنامه سازی لینوکس
وهمچنین ستون اول يك فونت ميتواند برای يك ستون تعريف شده باشد .تشريح tblبرای
cifceيك ستون از چپ مرتب شده در فونت cwچاپ ميکند.
متن جدول به همراه اطلعات فرمت کننده ميآيد .کارکتر تب ستونها را مجزا میك ند و برخي ازفرمانهای troffمانند .spدر داخل
جدول ابل درك هستند .به علمت هايي -و == توجه کنید کهدر ستون به tblمي گويد سطرهايي را در عرض جدول با اين پونت
بکشtbl .جدولهای متنوع وعريضتر ی را نسبت به مثال سادهای که بیان شد تشکیل ميدهد و حتي ميتواند متن جداخلمستطیل را
پر کند .عناوين ستون را مرتب کند و غیره ساده تارين راه برای استفاده از آن درجدولهای پیچیده جستجوی مثال مشابهي ست در
برنامههای يونیسك volume 2Aunixوتطبیق فرمان هاست.
عبارات رياضي
دومین پیش پردازنده troff، eqnاست که يك زبان توضي دهنده عبارات رياضي را به فرمانهایtroffبرای چاپ آنها تبديل ميکند .به
صورت خودکار تغییرات فونت و سايز ر ا دست کاری کردهو برای کارکترهای رياضي استاندارد نامي فراهم ميکند .ورودی
eqnمعمولً بین سطرهایEQو ENظاهر ميشود و .TSو TEرا قیاس ميکند.
EQ
IX SUB
EN
برای مثال فرمان بال xiرا ميسازد اگر بسته ماکروی msمورد استفاده قرار گرفته باشد .معادله بهعنوان يك نمايشگر چاپ ميشود و
يك نشانه گزينهای برایEQيك شماره معادله مشخصميکند برای مثال انتگرال زير:
زبان eqnبر پايه روشي قرار دارد که با صدای بلند رياضي صحبت ميکند .تفاوت بین رياضيصحبت شده و ورودی eqnآکولد است
که برایeqnپرانتز محسوب ميشود -آنها قواعاد تقدمپیش فرض زبان را قطع ميکنند -البته پرانتزها اهمیت خاصي ندارند .جايس
خاليها عموماًمهمترند توجه کنید که اولین zetaتوسط جای خاليها در مثال بال احاطه شده واژههای کلیدیمثل zetaو overتنها وقتي
تشخیص داده ميشوند که توسط فضاهای خالي و يا آکولدها احاطهشده باشند و نه هر چیزی که در خروجي باشد .
برای وارد کردن فضای خالي به خروجي از يك کارکتر که به صورت استفاده کنید .
برای تشکیل آکولد اينگونه استفاده کنید.
{}and
دسته بندی متعددی از واژههای کلیدیـ eqaوجود دارد .حروف هايب يوناني با حروف کوچكيا بزرگ استفاده ميشود .مانند
lambdaو LAMBDAکارکترهای رياضي ديگر دارای نام هستندمانند grad,infinty,int,sum
314/322 محیط برنامه سازی لینوکس
اپراتورهايي شبیهـ eqrtو پرانتزهای قابل گسترش ،آکولدها و ...وجود داردeqn .ستونها وماتريسهای موضوع را خواهد ساخت.
فرمان هايي برای کنترل فونت و سايز و موقعیت وجوددارد برای وقتیکه پیش فرضها صحیح نباشد.
قرار دادن عبارات رياضي کوچك مانند )log)nدر اصیل متن رايجتر است تا در نمايشگرها.واژههای کلیدی eqnبرای delimيك جفت
کارکتر مشخص ميکند به منظور در پرانتز قرار دادنعبارات خطي .اين کارکترها که به عنوان فاصلههای چپ و راست استفاده ميشوند
معمول شبیهبه هم هستند .علمت دولر$اغلب مورد استفاده قرار ميگیرد .البته hocاز $ژبرای نشانههایاستفاده ميکند ما از در مثال
هايمان استفاده ميکنیا .نیز برای جداسازی مناسب است بسیاری ازکارکترها دارای موجودی ويژهای در برنامههای متنوع خود هستند
که ميتوانند رفتارهای غیرعادی تماشايي را به دست دهد.
بنابراين بعد از بیان:
EQ
delim
EN
عباراتي خطي نظیر ميتواند اينگونه چاپ شود.
فرمان (صفحه )305
اين جدول همچنین نشان ميدهد که چگونه tblپونتهای ده دهي را در ستونهای عددی بهخط ميکند .خروجي جدول 3را به
دست ميدهد.
در نهايت تا زمانیکه eqnهر رديف از حروفي را که مشخص نیست ايتالیك ميکند ايتالسیك کردهواژههای که از eqnاستفاده ميکند
روشي رايج و معمولي است.
برای مثال به صورت wordچاپ ميشود .پس مراقب باشید eqnبسیاری از واژههای معمولي راتشخیص ميدهد مانند to froو با آنها
رفتار خاصي دارد ،و فضاهايي خالي را حذف ميکند.بنابراين در حین استفاده از اين راه کار دقت کنید.
خروجي :
شما بايد تمامي پیش پردازندهها وـ troffرا برای به دست آوردن خروجي ،رديف و به خط کنید .وباد فايلتان را آماده سازيد.
tblدرخواست فرمان هاست .سپس eqnو پس از آن troffاست .اگرتنها از troffاستفاده ميکنید تايپ کنید.
)troff-ms filenames )or-mm$
در غیر اين صورت شما بايد نام فايلهای نشانه را برای فرمان اول در مسیر اطلعاتي مشخصکنید واجازه دهید ديگران ورودی
استاندارد خود را بخوانند.
eqn filenames :troff -ms
or
tbl file names: eqn:troff-ms
315/322 محیط برنامه سازی لینوکس
ما دريافتیم که نوشتن برنامهای به نام doctypeمفید است که مراتب فرمان را استنباط ميکند(.فرمان صفحه )306
doctypeتوسط ابزارهايي که در فصل 4بحث شد تحقیق مييابد .به خصوص يك برنامهawkمراتب فرمان را جستجو ميکند .که اين
مراتب مورد استفاده پیش پردازندهها ست و سطرفرمان را به منظور راه اندازی اين نیازها و فرمت کردن فايل چاپ ميکند .همچنین
فرمان
ppرا که توسط بستههای ام اس( )msدرخواستهای فرمت کننه مورد استفاده قرار ميگیرد راجستجو ميکند.
(گزينه -nبرای egreeباعث ميشود که عنوان گذاری برای هر نام فايل بر روی هر خطي متوقفشود .متاسفانه اين گزينه برای همه
طرحهای سیستم وجود ندارد) ورودی اسکن ميشودمجموعه اطلعات بر روی جزئیات مورد استفاده قرار ميگیرد .بعد از اينکه کل
ورودی امتحانشد در تربیت راست برای چاپ خروجي پردازش ميشود .جزئیات توسط پردازندههایاستاندارد برای فايلهای تروفt
roffفرمت کننده مشخص ميشوند .ولي به طور کلي بگذاريد کهدستگاه مراقب جزئیات باشد.
doctypeمانند bundleمثالي است که از يك برنامهای را ميسازد .گرچه اين برنامه نوشته شدهاست اما نیازمند است که يك کاربر
سطر را در شل دوباره تايپ کند.
وقتي که فرمانـ troffاجرا ميشود شما بايد در نظر داشته باشید که رفتار roffبه صورت يك سیستموابسته است .در بسیاری از
تاسیسات خود سیستم حروفچین را مستقیما ً به کار مياندازد .درحالیکه در سیستمهای ديگر اطلعات بر روی خروجي استاندارد آن
ساخته ميشود که بايدتوسط يك برنامه مجزا بر روی حروفچین قرار گیرد.
به هر حال اولین شکل از اين برنامه از egrepو sortاستفاده نکردawk .به تنهايي تمامي ورودیرا اسکن کرد .و آن را برای يك فايل
بزرگ آرام و آهسته کرد .بنابراين egrepرا برای يك تحقیقسريع اجرا کرديم و sortرا برای خلص شدن از کپيها .برای فرمانهای
عادی دو فرايند ساختهشده اضافي برای غربال کردن دادهها کمتر است از اجرای awkبر روی بسیاری از ورودیها .دراينجا مقايسهای
بین doctypeو يك طرح که تنها awkرا اجرا ميکند نشان داده شده و درمحتوای اين فصل نیز استفاده شده است.
از قرارمعلوم اين مقايسه برای طراحي که از سه فرايند استفاده ميکرده مطلوب بوده است .و اينعملیات در ماشین توسط يك کاربر
انجام شده است توجه کنید که ما ابتدا به يك طرح سادهدارای کارايي دست يافتهايم قبل از آنکه بهینه سازی را آغاز کنیم .
49صفحه راهنما
مهمترين مستندات برای يك فرمان معمولً صفحه راهنما ميباشد توصیف يك صفحهای درراهنمای برنامه ريز usr\manبرنامه ريزی (
\UNIXصفحه راهنما در دايرکتری استاندارد ذخیرهميشود .معمول ً \usr\manدر يك دايرکتری فرعي طبق بخشهای راهنما شماره
گذاریميشود .صفحه راهنمای nocچون که فرمان کاربر را توضیح ميدهد به اين صورت نگه داریميشود.
\usr\man\man1\noc.1
صفحه راهنما ،فرمان )man)1را چاپ ميکند .يك فايل ،شلman-nroffرا اجرا ميکند.بنابراين mannocراهنمای nocرا چاپ ميکند
اگر برای يك بخش بیش از يك نام آورده شد بههمان صورت برای manنیز ميشود (بخش 1فرمان را توضصیح ميدهد در حالیکه
بخش 7ماکروها را توضیح ميدهد) بخش ميتواند manرا مشخص کند.
man 7 man
فرمان بال را تنها توصیف ماکروها را چاپ ميکند اقدامات پیش ساخته بايد تمامي صفحه را بانامهای مشخص شده چاپ کنند با
316/322 محیط برنامه سازی لینوکس
sll name
ed\teat editor
sh synopsis
Bed
I
B\-X
NAMEI
NAME
ed-text editor
synopsis
به کاربرد نسبت به شکل ساده دقت کنید.
قسمتـ DESCRIPTIONفرمان و گزينهاش را تعريف ميکند .در بسیاری از موارد توصیفي ازفرمان است نه زباني که فرمان را
توضیح ميدهد و صفحه راهنمای
)cc)1زبان cرا تعريف نميکند .او بیان ميکند که چگونه برای ترجمه برنامههای cفرمان ccراميتوان اجرا کرد و چگونه ميتوان بهینه
سازی را راه اندازی کرد در جايي که خروجي در چپاست و زبان در راهنمای مرجع مشخص شده و در قسمت seealsoکه مربوط
بهـ )cc)1مي شودذکر شده است .به عبارت ديگر مقولههای مطلق نیستندـ )man)7توصیفي از يك زببان راهنمایماکروهاست .به
317/322 محیط برنامه سازی لینوکس
صورت قراردادی در قسمت DESCRIPIIONنامهای فرمان و بر چسبهایگزينههای به صورت ايتالیك چاپ ميشود ماکروهای
Iکه اول نشانهها را به ايتالیك تايپ ميکندوـ RIکه اول نشانهها را به ايتالیك و سپس به لتین تايپ ميکند اين عمل را ممکن
ميسازدماکروی RIوجود دارد به خاطر اينکه ماکروی Iدر بستههای manبا آن سهیم نميشود.
قسمت filesهر فايلي را که به طور صفتي توسط فرمان استفاده ميشود را ذکر ميکند .اگرخروجي غیر عادی که توسط فرمان ساخته
شده است وجود داشته باشد نیاز است که مشمولآن شود که اين ميتواند يك پیام عیبشناسي باشد.
قسمت BWGSاندکي ناشناخته است .عیب و نقصهای گزارش شده زياد هم دارای خخطا واشتباه نیستند.
و به عنوان يك خطای جزئي و ساده ميبايست قبل از اينکه فرمان نصب گردد بهبود يابد برایاينکه بدانید چه چیزی وارد قسمت
BWGS,DIAGNOSTICSممي شود بايد در راهنمایاستاندارد جستجو کنید .يك مثال توضیح دهد که چگونه ميتوان يك صفحه
راهنما نوشت.برنامهای برای \ )uis\man\man1\hoc\hoc)1در شکل 9-1و 9-2نشان داده شده است.
نام
:hocزبان پونت شناور کننده واکنش
خلصه:
[hoc]file
توصیف:
nocيك زبان ساده را برای يك پونت شناور کننده حسابي تفسسیر ميکند ،که در مورد سطحبیسیك است در نحو و
عملکرد و روش شبیه به cمي باشد .و دارای نشانه و خاصیت بازگشتياست.
nocورودی استاندارد را تفسیر ميکند.
ورودی nocشامل عبارات و بیاناتي ست .عبارات ارزيابي شده است و نتايج آن چاپ شدهعبارات به ويژه نسبت دهيها
عملکردها و يا توضیح روسشها تا زماني صريحاً چاپ نشودخروجي را تشکیل نميدهد.
SEE Also
:nocزبان واکنشي برای پونتهای شناور کننده حسابي توسط Rob pike,Briankerrighan
خطاها :
5-9ديگر ابزار آماده سازی فايل :برنامههای ديگری برای آماده سازی فايل وجود دارد .فرمانتوسط واژههای کلیدی به مرجع نگاه
ميکند و دست آخر استنادهای خطي و قسمت مرجع را بهفايل شما نصب ميکند.
برای توصیف ماکروهای مناسب شما ميتوانید تربیتي دهید که referمرجعها را به همان سبكمورد نظر چاپ کند.
توضیحاتي برای تنوع ژورنالهای علمي کامپیوتر وجود دارد referقسمتي از است و برایبسیاری از طرحها انتخاب شده است.
بر روی تصاوير همان کاری را ميکند که معادلها انجام ميکدده تصاوير نسبت به معادلهها بسیراپیچیدهتر هستند حداقل در حد
حروفچیني و هیچج روش شفاهي چگونگي صحبت در مرودتصاوير وجود ندارد .بنابراين زبانها برای يادگیری و استفاده از آن
318/322 محیط برنامه سازی لینوکس
کارهايي انجام دادهاند در اينجا يك تصوير ساده و عبارات مربوط به آن در وجود دارد.
تصويرهای اين کتاب همگي توسط pic,deapicانجام شده که جزئي از نميباشد اما قابلدسترسي هستند.
چکیدهHOC :يك مفسر برنامهپذير ساده است که عبارات پونت را شناور ميکند که دارای روندکنترل به سبك cتعريف و عملکردها
و عملکردهای پیش ساخته عددی عادی است مانندکوسینوس و لگاريتم.
- 1عباراتHOC :زبان عبارات است مانند که در ان چندين عبارت کنترل روند و بیاناتي شبیهنسبت دهي که عباراتي هستند که به
میزان آنها تنوجهتری شده است برای مثال اپراتور سینوسدهي میزان عملوند راستش را به عملوند چپش نسبت ميدهد و میزانش
محصول و بهره ميدهد.گرامر عبارات اينچنین است:
number
vaviable
()eapr
enpr binop enpr
unop enpr
function
اعداد پونت را شناور ميکند .فرمت ورودی که توسط تشخیص داده ميشود ارقام پونت دهياعداد توان علمت دار حداقل يك رقم
و يا يك پونت ده دهي وجود داشته باشد بقیه عاملهاگزينشي هستند.
اسامي متغیر فرمهای فرمت شدهای هستند که يك حرف توسط يك رديف حرف و يا رقم دنبالميشودbinop .به اپراتورهای ده دهي
مانند مجموع و يا مقايسه منطقي رجوع ميکندunop .بهدو اپراتور منفي سازی رجوع ميکند .منفي سازی منطقي notو منفي سازی
حسابي تغییرعلمت جدول 1اپراتورها را لیست کرده است.
319/322 محیط برنامه سازی لینوکس
جدول :1اپراتورها
))**FORTRANبه توان رساني ^
منفي سازی حسابي و منطقي !
تقسیم ضرب *\
تفريق ،جمع -+
اپراتورهای نسبي بزرگتر و بزرگتر مساوی <<=
کوچکتر و کوچکتر مساوی >>=
مساوی .نامساوی==!=
منطقیو( همه عملوندها ارزيابي شدهاند)&&
منطقي يا همه عملوندها ارزيابي شدهاند
نسبت دهي متناظر=
عملکردها همان گونه که قبل ً توضیح داده شد ممکن است توسط کاربر تعريف شود نشانههایعملکرد عباراتي هستند که توسط کاما
( )،جدا ميشوند .تعداد زيادی عملکردهای از پیشساخته وجود دارد که همه آنها تنها دارای يك نشانهاند که در جدول 2توضیح
داده شده است.
عبارات منطقي دارای میزاني برابر 1/0صحیح و 0.0غلط است همچنین در cهر میزان صفحهی که برداشته ميشد صحیح بود.
همچنین HOCدارای مقداری محتوای از پیش ساخته است که در جدول 3نشان داده شدهاست.
expr
variable expr
(pyocedur )arglist
while
if)expr(stmt else stmt
stmtlist
print expr list
return optional-expr
nothing
stmlist stnt
يك نسبت دهي توسط پیش ساختهها به عنوان عبارتي تجزيه و تحلیل ميشوئد تا يك عبارت.بنابراين نسبت دهي ای که تايپ شده
میزان خود را تايپ نميکند.
توجه داشته باشید که سمي کامن در تنها در hocوجود ندارد .عبارات با سطر جديد پايانميپذيرند که موجب اجرای رفتار خاصي
ميشود.
بیانات عبارات ifاست که مجاز نیز ميباشد.
(if )x<0(print)>( else print)z
(if )x<0
else
(print)z
در مثل آکولدها دارای احکام و دستوراتي هستند .خط جديد بعد از ifعبارت را پاين ميدهد ويك خطای نحوی ميسازد که پرانتز را
حذف ميکند.
نحو و معناشناسي مهارتهای روند کنترل hihاساسا ً شبیه به cاستwhile.و ifنیز در وجود داردبا اين تفاوت که انقطاع و يا دنباله
کلم در آن وجود ندارد.
عملکرد ورودی خواندن مانند بقیه پیش ساختهها تنها يك نشانه بر ميگزينند .بر عکس بقیهپیش پردازندهها نشانهها يك عبارت نیستند
بلکه نام متغیرهاست .شماره بعدی همانطور که دربال تعريف شده از ورودی استاندارد خوانده ميشود و به متغیرهای نام گذاری شده
نسبت دادهميشود .میزان بازگشت صحیح است اگر میزان آن خوانده شده باشد و غلط است اگر به پايانفايل و يا يك خطا مواجه شده
باشد.
خروجي با عبارت تولید ميشود نشانههای کاما جدا شده در لیست عبارات و يك گیومه دو تاييمانند سطر جديد بايد فراهم شود
آنهاهیچگونه به طور خودکار فراهنم نميشود.
321/322 محیط برنامه سازی لینوکس
4روشها و عملكردها
روشها و عملکردها در hocمتمايز هستند گرچه آنها با يك مکانیسك مشابهي تعريفميشوند.اين تمايز برای چك کردن خطای زمان
اجرااست .اين خخطا برای روش بازگشت بهمیزان است و برای عملکرد بازگشتي نیست.
نحو تمايز اين گونه است:
functron func name )(stmt
procedur proce mame)(stmt
اسم ممکن است اسم هر متغیر عملکرد از پیش ساخته باشد که مستثني شده است.
بر عکس cاصل عملکرد و يا روش کار ميتوان هر بیاني باشد و نه الزام ًا يك بیان مرکب و مختلطتا زمانیکه سعي در مفهومي ندارد تنه
اصلي روش خالي با يك جفت آکولد خالي فرمت ميشود.
عملکردها و رويهها ممکن است نشانهای گزينش کنند که وقتي راه اندازه ميشوند توسط کاماهامجزا ميشوند .نشانهها به عنوان يك
شل رجوع داده ميشوند3$ .به سومین نشانه رجوع ميکند.آنها توسط میزان گذارنده ميشوند عملکردها نیز با متغیرها همتراز هستند.
رجوع به يك نشانهشماره گذاری شده بزرگتر از شماره نشانه هايي که توسط روال کار گذرانده ميشود اشتباه و خطااست .چك کردن
خطاها به صورت پويا انجام ميپذيرد گرچه ممکن است روال کاری شمارههایمتغیر نشانهها را داشته باشد اگر نشانه اصلسي
ونخستین بر روی شماره شناسهها به منظور رجوعشدن تاثیر بگذارد.
عملکردها و رويهها ممکن است باز گردند .ام پشتهها stackاز نظر عمق محدود شدهاند .در زيرتعريف hocدر عملکرد Ackermann
نشان داده شده است.
hoc
}()func ack
if )$ 1==0(return$s
if)$2=0( return ack
(return ack)$1-1,ack)$1,$2-1
(ack)3,2
29
ack)3.3
61
(ack)3,4
hoc:sta ek too deep hear line 8
.....
5مثالها
فرمول استرلینگ
n!2n
322/322 محیط برنامه سازی لینوکس
hoc
func stirl )(}
return sqrt)2*$1*pi(
{
stirl)20(
2.4328818e+18
!n :عملکرد فاکتوريل
i=9
while)li=i+1(<=20(}
print,fac)i(stirl)i(in
{
10 1.0000318
11 1.0000205
12 1.0000224
13 1.0000166
14 1.0000146
16 1.0000128
17 1.0000114
18 1.0000102
19 1.000092
20 1.000083