!" #
&'( $ % )
* + , -!
محیط برنامه سازی لینوکس
1/322
فصل یک :لینوکس براي مبتدیان يونیکس چیست؟ به معنای دقیق ،اين برنامه هسته سیستم عامل اشتراك زماني ،است ،يعني برنامهای که منابع کامپیوتر را کنترل ميکند
و آنها را در بین کاربرانش ،تخصیص ميدهد .اين برنامه به کاربرانش اجازه مي دهد که برنامههايشان را اجراء کنند ،و وسايل جانبي
(ديسکها ،پايانهها ،چاپگر و از اين قبیل وسايل) را که به سیستم ارتباط دارد را کنترل ميکند و فايل سیستمي را فراهم ميآورد که
ذخیره سازی طولني مدت اطلعاتي همچون :برنامهها ،دادهها و اسناد را کنترل کند .به معنای کلي ،يونیکس غالباً نه تنها شامل اساس و شالوده است بلکه ،شامل برنامههای ضروری همچون :مترجم (مفسر) ،ويراستار ،زبانهای فرمانها ،برنامههايي جهت کپي و چاپ
فايلها و از اين قبیل خدمات است .باز هم به معنای وسیعتر ،يونیکس حتي شامل برنامههای توسعه يافته توسط شما و يا ديگر کاربراني
است که اين برنامهها را در سیستم شما ،بدون وقفه اجراء ميشوند ،برنامههايي همچون :ابزارهايي برای تهیه اسناد ،مراحلي برای
تجزيه تحلیل آماری و بستههای نرم افزاری تصاوير (طرحها) .کدامیك از اين استفادههايي که از سیستم يونیکس مطرح شد ،با توجه به
سیستمي که شما در حال استفاده از آن هستید ،صحیح است .زماني که ما از اصطلح يونیکس در مابقي اين کتاب استفاده ميکنیم،
محتوای کتاب بايد آن معني را که ضمني است ،مطرح کند .سیستم يونیکس بعضي اوقات درمقايسه با آنچه که هست ،مشکل تر به نظر ميرسد ،يعني برای مبتديان درك چگونگي بهترين استفاده از امکانات موجود ،مشکل است .اما خوشبختانه ،شروع کار با آن سخت
نیست ،تنها اطلع و دانش پیرامون چندين برنامه باعث راه افتادن شما در استفاده از اين سستم ميشود .اين فصل وسیلهای است برای کمك به شما در جهت شروع هر چه سريعتر استفاده از سیستم .اين فصل به عنوان بررسي کلي است نه راهنمای استفاده ،ما در نظر
داريم که مطالب را به صورت جزئيتر در فصول بعدی دوباره ،مطرح کنیم .ما در نظر داريم که در مورد اين عرصههای وسیع صحبت
کنیم :
•مباني اصلي :شامل وارد شدن و خارج شدن از سیستم ،فرامین ساده ،تصحیح خطاهای تايپ ،پست الکترونیکي، ارتباطات بین پايانهای ،است.
•استفادة روز به روز ،شامل موارد زير است :شامل ،فايلها و فايل سیستم ،فايلهای چاپگر ،فهرست راهنماها ،فرامین مورد استفاده عادی.
•فرمان مترجم (مفسر) يا shellشامل موارد زير است :
مختصر نويسي نام فايل ،تغییر جهت ورودی و خروجي ، Pipes ،پاك کنندههای محیط و از بین بردن نمادها و تعريف مسیر جستجو برای فرامین.
اگر شما از يك سیستم يونیکس استفاده ميکنید( ،از آنجايي که اغلب قسمتهای اين فصل برای شما آشنا است) مستقیماً به سراغ فصل
2برويد .شما به يك کپي از فهرست راهنمای برنامهساز يونیکس نیاز خواهید داشت ،حتي زماني که شما اين فصل را مطالعه ميکنید،
غالبا ً بیان اين امر که بهتر است ،حتي زماني که شما اين فصل را مطالعه ميکنید ،غالبا ً بیان اين امر که بهتر است شما برخي از مطالب
موجود در فهرست را به جای تکرار آنها در اينجا مورد مطالعه قرار دهید ،برای ما امری آسانتر به نظر مي رسد .اين کتاب در نظر ندارد
که آن مطالب را جايگزين کند ،بلکه در نظر دارد که به شما چگونگي بهترين استفاده از فرامین توصیف شده در آن ،را نشان دهد .علوه بر اين ،ممکن است تفاوتهای بین آنچه که ما در اينجا ميگوئیم و آنچه که در سیستم شما صحیح به نظر ميرسد ،وجود داشته باشد.
فهرست راهنما ،در شروع آنچه که برای يافتن برنامههای صحیح جهت کاربرد در رفع مشکل و فراگیری استفاده از آن ،ضروری به نظر
ميرسد ،دارای فهرست جابهجا شدهای است .نهايتاً ،يك توصیهای که لزم به نظر ميرسد اين است که از آزمايش کردن ،نترسید .اگر
محیط برنامه سازی لینوکس
2/322
شما يك مبتدی هستید ،مسائل تصادفي زيادی وجود دارد که شما ميتوانید با انجام آنها به خودتان يا ديگر کاربران آسیب برسانید. بنابراين ،چگونگي عملکرد آن مسائل را با تلش و کوشش بر روی آنها فرا گیريد .اين فصل ،فصل بسیار طولني است و بهترين راه برای مطالعه آن اين است که هر دفعه چند صفحه را مطالعه کنید و مادامي که به پیش ميرويد ،مطالب را مورد آزمايش و بررسي قرار دهید.
بخش 1 .1شروع كار برخي از مقدمات در مورد پايانهها و تايپ به منظور اجتناب از تشريح هر مورد پیرامون استفاده از کامپیوترها ،ما بايد فرض کنیم که
شما آشنايي مخصتری با پايانههای کامپیوتر و چگونگي استفاده از آنها داريد .در صورتي که هر کدام از جملت زير مبهم و پیچیده
باشد ،ما بايد به منظور درك آن از کارشناس سؤال کنیم .سیستم يونیکس ،سیستم دو طرفه کامل است ،يعني علئم و حروفي که شما از
طريق صفحه کلید ،تايپ ميکنید به سیستم انتقال پیدا ميکند ،به نحوی که سیستم آنها را به پايانهها به منظور چاپ بر روی صفحه
نمايش ،بر ميگرداند .به طور طبیعي ،اين فرايند انعکاس ،علئم و حروف را به طور مستقیم در صفحه نمايش ،کپي ميکند ،بنابراين
شما ميتوانید آنچه را که شما در حال تايپ آن هستید را ببنید اما ،بعضي اوقات همچون زماني که شما در حال تايپ يك کلمه رمز
هستید ،فرايند انعکاس قطع ميشود ،بنابراين علئم و حروف بر روی صفحه نمايش ،نمايان نميشود .اغلب علئم و حروف صفحه کلید ،بدون هیچ مفهوم خاصي از جمله علئم چاپي معمولي و رايج به شمار ميآيند ،اما تعداد کمي از آنها به کامپیوتر چگونگي تفسیر
تايپ شما را اعلم ميکند .به مراتب ،مهمترين اين موارد ،کلید 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
بحث پیرامون يونیکس آنچه را که، از طريق مثالهای موجود در اين کتاب، بحث را آغاز کنیم، اجازه دهید که با گفتگويي پیرامون شما و سیستم يونیکس تان
پاسخهای کامپیوتر به صورت علئمي به سك ماشین تحرير است و، شما تايپ کردهايد در حروفهايي به صورت موب چاپ شده است توضیحات و تعريف به صورت موب است
: سیستمتان بايد اين موارد را اعلم کند. شماره ای بگیريد يا دکمهای را در صورت لزوم روشن کنید: ارتباطي را ايجاد کنید
Establish a connection: dial a phone or turn on a switch as necessary. Yoyr system should say login: You Type your name, then press RETURN password: your password won`t be echoed as youe type it you have mail. There`s mail to be read after you lig in $ The system is now rady for your commands $ press RETURN a couple of times $ date What` the dte and time? sun sep 25 23:02::57 EDT 1983 $ who who`s using the machine? jlp tty0 sep 25 13:59 you tty2 sep 25 23:01 mary tty4 sep 25 19:03 doug tty5 sep 25 19:22 egb tty7 sep 25 17:17 bob tty8 sep 25 20:48 $ mail Read your mail From doug sun sep 25 20:53 EDT 1983 give me a call sometime monday ? RETURN moves on to the next message from mary sun sep 25 19:07 EDT 1983 Next message Lunch at noon tomorrow? ?d Delete this message $ No more this message $ mail mary send mail to mary lunch at 12 is fine ctl-d End of mail $ Hang up phone or turn off terminal and that`s the end مابقي اين بخش. همانگونه که بسیاری از افراد چنین ميکند،بعضي اوقات تمام مواردی که در اينجا بیان شد شامل يك مرحله است
. بحث ميکند،در مورد قسمت بال به علوه يدگر برنامههايي که آن برای انجام کارهای مفید ممکن ميسازد
محیط برنامه سازی لینوکس
4/322
ورود به سيستم شما بايد يك نام و يك کلمه رمز ورودی داشته باشید ،شما ميتوانید اين نام را از اسم يا برنامه نرمافزاری سیستمتان بگیريد .سیستم يونیکس قابلیت ارتباط با انواع وسیع پايانهها را دارد ،اما اين سیستم به طرز قابل توجهي در جهت ابزارهايي با حروف کوچك است،
يعني حروفي که مطالب را از يکديگر مجزا مي سازد ،اگر پايانه شما تنها حروف بزرگ ايجاد کند( ،مثل برخي از ويدئو و پايانه های
قابل حمل) زندگي آنچنان سخت خواهد شد که شما بايد به دنبال پايانه ديگری باشید .از دکمههايي که به طرز مناسبي بر روی وسیله
شما قرار گرفته است ،مطمئن شويد ،از حروف بزرگ و کوچك ،سیستم دو طرفه کامل و ديگر تجهیزاتي که کارشناسان به آنها توصیه ميکندن ،مثل سرعت يا سرعت باود نیز اطمینان حاصل کنید .با استفاده از هر عمل شگفتانگیزی که برای پايانه شما نیاز است،
ارتباطي را ايجاد کنید ،اين فرايند ممکن است شامل ارتباط تلفني يا صرفا ً ضربه زدن به يك دکمه باشد .در موارد ديگر ،سیستم بايد عمل تايپ را انجام دهد.
برقراري ارتباط اگر سیستم اطلعات غیرمفید ،تايپ کند ،احتمال ً نشان دهنده اين است که شما سرعت غلطي را انتخاب کردهايد ،محیط مربوط به
سرعت را و نیز ديگر دکمهها را چك کنید .اگر اين کار فايده نداشت ،کلید breakيا interruptرا چند بار آهسته ،فشار دهید .اگر
هیچکدام از اين کارها پیام ارتباط را نمايان نکرد ،فرد متخصصي را به کمك بگیريد .زماني که شما ارتباط برقرار کرديد ،پیامي به اين مضمون نمايان ميشود :
اسم ارتباطتان را با حروف کوچك تايپ کنید .به دنبال آن ،کلید Returnرا فشار دهید .اگر کلمه رمز نیاز باشد ،در مورد آن از شما
سؤال ميکند و عمل چاپ مادامي که شماآن را (کلمه رمز) تايپ ميکنید قطع ميشود .حداکثر تلشهای برقراری ارتباطتان به صورت پیام واره انجام مي شود .معمولً به صورت يك علمت تنها ،پیام واره نشان دهنده اين است که سیستم برای پذيرش فرامیني از جانب
شما آماده است .پیام واره غالبا ً شبیه يك علمت دلر $يا علمت درصد ( )%است .پیام واره به وسیله برنامهای که مترجم (مفسر)
پیامها يا shellنامیده مشود ،چاپ مي شود که اين برنامه واسط اصلي شما برای سیستم به شمار ميآيد .شايد پیامي از روز قبل از پیام
کنوني موجود باشد يا اطلعیه ای مبني بر اين که شما نامه داريد وجود داشته باشد .شايد بپرسید که شما اکنون در حال استفاده از چه نوع پايانهای هستید؟ پاسخ شما به سیستم برای استفاده از هر گونه خصوصیات که پايانه آنها را داراست ،کمك ميکند.
تايپ فرامين زماني که شما پیام واره ای را دريافت ميکنید ،ميتوانید فرامیني را تايپ کنید که اين فرامین عبارتند از درخواستهايي که سیستم آنها را انجام مي دهد .ما در نظر داريم که از برنامه ها به عنوان برنامههايي هم معنا و مشابه فرامین استفاده کنیم .سیستم بايد با زمان و تاريخ پاسخ دهد .سپس پیام ديگری را چاپ کند ،بنابراين تمام مذاکرات شبیه به اين مورد در پايانه شما خواهد بود :
$ date
محیط برنامه سازی لینوکس
Returnرا فراموش نکنید و $را تايپ نکنید.
5/322
Mon sep 26 12:2057 EDT 1983 $
اگر فکر ميکنید که عمل را اشتباه انجام دادهايد ،کلید Returnرا فشاردهید ،در اين مرحله بايد اتفاقي پیش آيد Return .بار ديگر نمايان نمي شود اما شما در پايان هر خط به آن نیاز داريد .فرمان ديگری که بايد انجام دهید ،عبارتست از whoکه اين فرمان هر فردی
را که در حال برقراری ارتباط است را معرفي ميکند :
$ who rlm tty0 sep 26 11:17 pjw tty4 sep 26 11:30 gerard tty7 sep 26 10:27 mark tty9 sep 26 07:59 you ttya sep 26 12:20 $ اولین ستون نام کاربران است ،دومین ستون نام سیستم برای ارتباط مورد استفاده است )tty( ] .به معنای دور تحرير ( )tele typeاست، هم معني قديمي برای پايانه[ .مابقي نشان دهنده زماني است کاربر ارتباط برقرار کرده است .ممکن است شما عمل زير را انجام دهید.
$ who am i you ttya sep 26 12:20 $ اگر شما نام فرمان را اشتباه تايپ کنید ،و به سراغ يك فرماني که وجود ندارد برويد ،ممکن است با خود بگوئید که هیچ فرماني که
تحت اين عنوانباشد ،يافت نميشود :
$ whom Misspelled command name .... whom: not found .... so system didn`t know how to run it $ البته اگر شما از روی بي دقتي ،نام فرمان اصلي را تايپ کرده باشید ،آن برنامه اجراء خواهد شد ،البته شايد با نتايجي مبهم.
رفتارهاي غير متداول پايانه ها بعضي اوقات پايانه شما ممکن است به طرز غیر متداولي عمل کند ،برای مثال هر حرف ممکن است دو بار تايپ شود ،يا Return
ممکن است ،مکان نما را در ابتدای ستون خط بعدی قرار ندهد .شما معمول ً ميتوانید اين جريان را با خاموش و روشن نمودن پايانه
تثبیت کنید يا با خارج شدن از ارتباط و سپس برقراری در ارتباط مجدد .يا مي توانید توصیف فرمان ( STTyتنظیم انتخابهای پايانه) که در بخش اول فهرست راهنما است ،را مطالعه کنید .به منظور کنترل ارتباطات از طريق مضخصه Tabدر صورتي که پايانه شما دارای
Tabsنباشد ،فرمان را تايپ کنید.
$ stty – tabs و سیستم
Tabsرا به تعداد صحیحي ا ز spacesتبديل خواهد کرد .اگر پايانه های شما دارای نقاط Tabقابل تنظیم کامپیوتری
باشند ،فرمان Tabsآنها را به طرز صحیحي برای شما تنظیم خواهد کرد( .شما بايد در مورد تايپ پايانه Tabs $به دقت عمل کنید ،تا
اين عمل انجام شود ،توصیف فرامین Tabsدر فهرست راهنما را مطالعه کنید).
محیط برنامه سازی لینوکس
6/322
خطا در فرايند تايپ اگر شما خطای تايپي داشته باشید و آن را قبل از اينکه کلید 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يا پسبرد) شده است ،که در پايانههای ويدئو به خوبي عمل ميکند .شما سريع ًا ميتوانید متوجه شويد که کدام مورد سیستم شما قرار گرفته است :
$ datee Try datee :not found It`s not $ datee# Try # Mon sep 26 12:26:08 it is # $ ما علمت backspaceيا پسبرد را به صورت چاپ کردهايم ،بنابراين ميتونید آن را ببینید) .انتخاب شايع ديگر عبارتست از CTL- Cبرای از بین بردن سطر .ما از علمت sharp #به عنوان مشخصه پاك کن برای مابقي اين بخش استفاده ميکنیم ،چرا که اين علمت
قابل رؤيت است ،اما در صورتي که سیستم شما متفاوت باشد ،تنظیمات پايانهای را انجام دهید .بعد ،در فرايند «اندازهگیری محیط» ما
به شما مي گوئیم که چگونه پاك کن و علمت از بین بردن سطر را برای آنچه که شما دوست داريد يك بار يا برای همیشه تنظیم کنید .
برای چه چیزی شما بايد پاك کن يا علمت از بین بردن سطر را به عنوان بخضي از متن ،وارد کنید؟ اگر شما #يا علمت @ را به وسیله back slashجلوتر قرار دهید ،اين امر باعث مي شودکه آن علمت معنای خاص خودش را از دست بدهد. بنابراين به منظور وارد کردن #يا @ \ @ يا \ @
را تايپ کنید .سیستم ممکن است مکان نمای پايانه را به سطر بعدی بعد از @ شما جلو ببرد ،حتي اگر آن توسط backslashجلوتر واقع شده باشد .در صورتي که علمت @ ثبت شود ،نگران نباشید Backslash .بعضي اوقات علمت escapeنامیده ميشود ،که به
محیط برنامه سازی لینوکس
7/322
میزان وسیع برای نشان دادن اين مطلب که علئم زير به طريقي خاص و ويژه هستند ،مورد استفاده قرار ميگیرد .به منظور پاك کردن backslashشما بايد دو علمت پاكکن را تايپ کنید .يعني #
\ #آيا ميدانید چرا؟ علئمي که شما تايپ کرديد مورد بررسي قرار
گرفته و بوسیله توالي برنامهها قبل از اينکه آنها به مقصدشان برسند ،تعبیر و تفسیر مي شوند.
و اينکه آنها دقیقا ً چگونه تعبیر و تفسیر ميشوند نه تنها به جايي که پايان مي پذيرند بستگي ندارد بلکه به چگونگي رسیدن به آن
مرحله نیز بستگي ندارد .هر علمتي را که تايپ ميکنید ،بلفاصله در قسمت پايانه انعکاس پیدا ميکند مگر اينکه روند انعکاسيابي
پايان پذيرد (پايانه خاموش شود) که اين شرايط بسیار نادر است .زمانیکه Returnرا فشار دهید علمتها به صورت موقتي توسط هسته
اصلي ( )kernelکنترل ميشوند ،در نتیجه غلطها تايپي ميتوانند با پاك کن و مشخصه از بین برنده سطرها ،تصحیح شوند .زماني که
پاك کن يا علمت از بین برنده سطر توسط backslashتقدم يابد ،هسته اصلي ( )kernelباعث ميشود که backslashکنار زده شده و بقیه علمتها را بدون تعبیر و تفسیر کنترل کند .زمانیکه Returnرا فشار دهید ،علئم حفظ شده به برنامه ای فرستاده مي شوند که از
پايان خوانده ميشود .آن برنامه نیز به نوبه خود ممکن است علئم و مشخصهها را به روشهای خاصي تعبیر و تفسیر کند ،برای مثال:
برنامه shellهرگونه تعبیر خاصي از علئم را در صورتي که توسط backslashتقدم يافته باشد را از بین ميبرد .در مورد اين موضوع
در فصل 3بحث خواهیم کرد .اکنون ،بايد به خاطر داشته باشید که ( kernelهسته اصلي) پاكکن و علمت از بین برنده سطرها را
پردازش ميکند و backslashتنها در صورتیکه پاك کن و علمت از بین برنده سطر را در تقدم قرار داده باشد ،هر علمتي را که بعد از
آن رها شده باشد را به وسیله برنامههای ديگری به خوبي تعبیر و تفسیر مي کند.
تمرين 1ـ .1توضیح دهید در صورتي که $
@ \ dateچه اتفاقي ميافتد.
تمرين 2ـ .1اغلب برنامههای ( shellاگر چه shellچاپ هفتم شامل آن نمي شود) علمت #را به عنوان معرفي به موضوع تعبیر
ميکنند ،و تمام متن را از علمت #تا پايان سطر ناديده ميگیرند .با توجه به اين موضوع ،نسخه زير را توضیح دهید ،فرض کنید که علمت پاكکن نیز به صورت #است :
1983 EDT 1983
$ date Mon sep 12 : 39 : 56 EDT $ # date Mon sep 26 12 : 24: 21 $ \ # 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در نظر گرفته شده است.
$ Eof $ همچنین ميتوانید از writeبا فشار دادن deleteخارج شويد .توجه کنید که خطاهای تايپي شما بر روی پايانه مری ظاهر نمي شود.
اگر شما در نظر داريد که به فردی که در ارتباط نیست نامه بنويید يا به فردی که نمي خواهد با کراه مناسب برای قطع کردن ارتباط
عبارتست از تايپ فرمان CTL-dبه جای فرمان وجود ندارد .به منظور پاسخ دهي ،فرمان write Mary $را تايپ کنید .اين عمل مسیر ارتباطي دو طرفهايي را بوجود ميآورد .اکنون سطرهايي را که مری بر روی پايانه خودش تايپ کرده بر روی پايانه شما نیز تايپ
ميشود و بر عکس ،اگر چه اين مسیر آرام و آهسته عمل ميکند اما تا حدی بیه به talking to the moonاست .اگر در اواسط کاری
قرار داريد ،شما مجبوريد در شرايطي قرار گیريد که بتوانید فرماني را تايپ کنید .طبیعتاً هر برنامه ايي که شما در حال اجرای آن هستید بايد متوقف شود اما برخي از برنامهها همچون ويراستار يا writeبه خودی خود ،دارای فرمان ( ! ) هستند که اين فرمان به طور موقتي
از برنامه shellخارج ميشود ،جدول 2را در قسمت ضمیمه 1مورد مطالعه قرار دهید .فرمان writeهیچ قانوني را وضع نمي کند،
محیط برنامه سازی لینوکس
9/322
بنابراين برای حفظ آنچه تايپ ميکنیم و جلوگیری از مخدوش شدن با آنچه که مری تايپ ميکند ،دستورالعملي لزم است .يك قانون
اين است که چرخشي کرده و هر چرخش را با ( ) 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فرستاده ميشود .راحت ترين وسادهترين روش عبارتست از:
اکنون در متن نامه هر تعداد سطری که ميخواهید تايپ کنید بعد از آخرين سطر نامه فرمان Gntrd-dرا تايپ کنید.
$ mail nico
$Ctl – d Ctl-dبه معنای پايان نامه به وسیله فرمان mailاست که بیان ميدارد هیچ ورودی ديگری موجود نميباشد اگر شما در نیمة راه
نظرتان را مبني بر ترکیب نامه تغییر داديد ،کلید deleteرا به جای ctl-dفشار دهید .نامهای که به صورت نیمه کاره شکل گرفته است
در فايلي که به نام dead.letterاست به جای فرمان انتقال ( )Sendذخیره ميشود .به عنوان تمرين،نامهای را برای خودتان بفرستید،
سپس،علمت mailرا جهت خواندن نامه تايپ کنید.
(اين عمل به آن اندازهای که به نظر ميرسد گمراه کننده نیست ،اين کار مکانیسم يادآوری مناسبي است) .روشهای ديگری برای
فرستادن نامه وجود دارد شما ميتوانید نامهای را که از قبل آماده شده است را بفرستید ،ميتوانید نامهای را به تعدادی از افراد مورد
نظرتان در يك زمان خاص بفرستید و ممکن است قادر باشید نامه را به افرادی در سیستمهای ديگر بفرستید .جهت اطلع از جزئیات
بیشتر نسخه فرمان mailرا در بخش 1فهرست راهنمای برنامهساز يونیکس مطالعه کنید .از اينجا به بعد ما از مفهم ( mail )1به معنای
صفحاتي که mailرا در بخش 1کتاب راهنما توصیف ميکنند ،استفاده ميکنیم همچنین ممکن است سرويس تقويم نیز وجود داشته باشد ( بخش ،تقويم 1را مطالعه کنید) و ما در فصل 4به شما نشان خواهیم داد که نامه چگونه در صورتي که پیش از اين کاری بر
روی آن انجام نگرفته است ،تنظیم ميشود.
نوشتن نامه به كاربر ديگري از سیستم يونیکس شما دارای چندين کاربر است .روزی ،ناگهان.پايانه شما پیغامي شبیه به اين موضوع چاپ خواهد کرد:
محیط برنامه سازی لینوکس
11/322
message from mary tty 7
که اين پیغام با صدای بوق قابل توجهي همراه است .مری ميخواهد که به شما نامهای بنويسید ،اما در صورتي که شما عمل واضحي
انجام ندهید ،امکان اينکه شما قادر به پاسخ دهي باشید man who $ ،را تايپ کنید و البته man man $ ،در مورد فرمان فرد مورد نظر
اطلعاتي ميدهد.
دستورالعملهای کمك کننده به کامپیوتر
سیستم شما ممکن است دارای فرماني باشد که Learnنام داد که اين فرمان دستورالعملةای کمك دهنده به کامپیوتر را بر روی فايل سیستم و فايلهای اصلي ويراستار ،آماده سازی اسناد و حتي برنامه Cفراهم ميآورد.
فرمان learn $را تايپ کنید .اگر فرمان Learnدر سیستم شما باشد ،در اين صورت آنچه را که شما بايد از آنجا انجام دهید را به شما
اعلم ميکند .در صورتي که اين فرمان اجرا نشود در مورد فرمان teachاقدام کنید.
بازيها بازيها همیشه پذيرفته شده نیستند امايکي از بهترين راهها برای کسب آسايش و راحتي از کامپیوترها و پايانهها ،اجرای بازيها است.
سیستم يونیکس با تجهیزات معمولي از بازيها همراه است و غالبا ً اين تجهیزات به صورت محلي ضمیمه ميشوند .اطراف را مورد بررسي قرارداده يا بخش 6فهرست راهنما را مورد مطالعه قرار دهید.
2ـ ) 1استفاده روز به روز :فايلها و فرامين معمول اطلعات در سیستم يونیکس در فايلها ذخیره ميشود ،که بیشتر شبیه به فايلهای اداری معمولي هستند .هر فايل دارای نام ،محتوا و مکاني برای حفظ آن است و برخي از اطلعات اداری ( اجرايي) همچون فردی که مالك آن است و میزان بزرگي آن ،ميباشد فايل ممکن است دارای نامه يا لیستي از نامها و آدرسها باشد يا منبع اطلعات برنامهها يا اطلعاتي که بايد به به وسیله برنامه استفاده شود يا
حتي دارای برنامه ها به شکل قابل توجیه و ديگر موضوعات غیر متني باشد .فايل سیستم يونیکس به صورت سازمان يافته است.
بنابراين شما ميتوانید فايلهای شخصي خودتان را بدون مداخلت با فايلهای متعلق به افراد ديگر حفظ کنید و افراد را از دخالت پیدا
کردن در مورد فايلهای خودتان منع نمائید .تعداد زيادی برنامه وجود دارد که فايلها را کنترل ميکند .اما اکنون ما تنها به اکثر آنهايي که
به طور مکرر توسط افراد مورد استفاده قرار ميگیرد ،سرورکار داريم .فصل 2شامل بحث سیستماتیکي در مورد فايل سیستم است و بسیاری از ديگر فرامین مربوط به فايلها را معرفي ميکند.
ايجاد فايل ـ فايل ويراستار
در صورتي که بخواهید برگه يا نامه و يا يك برنامه را تايپ نمائید .چگونه اطلعات ذخیره شده در ماشینـ ( سیستم) را بدست
ميآوريد؟
اغلب اين کارها با فايل ويراستار متن که برنامهای برای ذخیره کردن و کنترل اطلعات در کامپیوتر است انجام ميگیرد ،تقريبا ً هر
سیستم يونیکس دارای ويراستار صفحه نمايش است ويراستاری که مزيتهايي را از پايانههای مدرن گرفته وبدين وسیله تأثیرات تغییرات ويراستاری شما را در متن همزمان با بوجود آوردن متن ،نشان ميدهد .دو نمونه از مشهورترين اين فايلها عبارتند از emacs,viما در
محیط برنامه سازی لینوکس
12/322
نظر نداريم که هیچ نوع ويراستار صفحه نمايش خاصي را در اينجا تشريح کنیم ،و اين امر تا حدی به دلیل محدوديتهای حروف چیني
و تا حدی به دلیل عدم وود نوعي استاندارد است .با اين وجود يك نمونه ويراستار قديميتر که edنامیده ميشود وجود دارد که
مطمئنا ً برروی سیستم شما موجود است .اين نوع ويراستار هیچ گونه مزيتي از خصوصیات پايانههای دريافت نکرده است ،بنابراين بر
روی هر گونه پايانهای کار خواهد کرد .اين فايل همچنین اصولي از ديگر برنامههای ضروری را تشکیل ميدهد( شامل برخي از
ويراستارهای صفحه نمايش ) بنابراين فايل ارزش يادگیری را دارد .ضمیمه 1شامل نسخة مختصری از اين فايل است .اين که شما چه
نوع ويراستاری را ترجیح ميدهید مهم نیست ،بلکه مهم است که شما آن را به خوبي فرا گرفته تا بتوانید فايلهايي را ايجاد نمائید .در
اينجا ما از فايل edجهت ارائه بحث استفاده ميکنیم و مطمئن هستیم که شما ميتوانید مثالهای ما را بر روی سیستمتان اجرا نمائید اما
حتما ً از ويراستاری که بهتر دوست داريد استفاده نمائید .به منظور استفاده از edجهت ايجاد فايلي که junkنامیده ميشود ( به همراه متوني در آن ) کارهای زير را انجام دهید:
فرمان edويراستار متن را به منظور
$
ed
افزودن متن به کمك بطلبید a
اكنون در هر متني كه ميخواهيد تايپ کنید.
•
به وسيله خودش ’
.
‘ را به منظور متوقف نمودن
افزايش متن،تايپ کنید .متن تان را در فايلي که
تحت عنوان junkاست،بنويسیدq .
تعدادی از علئم نوشته شده را چاپ ميکند.
w junk 39 ed $
از 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 ،باعث ميشود که فايلها به ترتیب زماني فهرست شوند: ترتیبي که در آن آنهايي که آخر تغییر يافتهاند غالب ًا جديدتر بوده و در اولويت آخر هستند.
انتخاب 1ـ فهرست طويلي را نشان ميدهد که اطلعات زيادی در مورد هر فايل فراهم ميآورد.
$ 1s-t Temp Junk $
محیط برنامه سازی لینوکس
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
فايلهای چاپگر ـ cat , pr
اكنون شما داراي برخي از فايلها هستيد ،اكنون چگونه شما محتواي آنها را مورد بررسي قرار دهيد ،برنامههاي زيادي وجود دارد كه اين كار ر انجام ميدهد ،كه احتمالً اين عمل بيشتر از مورد نياز است .يكي از اين امكانات اين است كه از ويراستار استفاده كنيد: edبه تعداد 19كاراكتر را در junkثبت ميكند سطر 1تا آخر را چاپ ميکند و فايل تنها يك سطر دارد
تمام کارها انجام گرفته است
$
junk
ed
19 p$ , 1
باشد يا نباشد
q $ edبا ثبت تعدادی از کاراکترها در junkشروع به کار ميکند فرمان p ، 1$اظهار دارد که آن تمام سطرها را در فايل چاپ کند .پس از
اينکه فراگرفتید چگونه از ويراستار استفاده کنید ،ميتوانید به صورت انتخابي در موردبخشهايي که چاپ مي کنید ،عمل کنید ،زماني که
امکان استفاده از ويراستار برای چاپ وجود نداشته باشد موقعیتهايي وجود دارد .برای مثال،در مورد میزان بزرگي فايل edکه بتواند مورد استفاده قرار گیرد،محدوديتهايي وجود دارد ( چندين هزار سطر) علوه بر اين ،اين فايل تنها يك فايل را در يك زمان چاپ ميکند ،و بعضي اوقات شما ميخواهید چندين فايل را چاپ کنید به صورتي که يکي پس از ديگری بوده و هیچگونه توقفي در حین
چاپ وجود نداشته باشد .بنابراين در اين زمینه مجموعهای از راهحلها وجود دارد .اولین مورد فايل couاست ،که اين فايل از تمام
فرامین چاپ سادهتر است .اولین مورد فايل تمام فايلهايي که توسط شناسههايشان نام گذاری شدهاند را چاپ ميکنید :
فايل نام گذاری شده يا فايلها در پايانه يکي پس از ديگری بدون وقفه و فاصله الحاق ميشوند،
$ cat junk To be or not to be $ cat Temp That is the question $ cat junk Temp To be or not to be That is the question $
( از اين رو نام « »catانتخاب شده است) در مورد فايلهای کوتاه مشکي وجود ندارد اما برای فايلهای بزرگ مشکل پیش ميآيد در
صورتي که شما با سرعت بسیار بال به کامپیوترتان متصل شويد ،بايد سريع ًا Ctl-sرا برای متوقف کردن خروج از Catقبل از اينکه اين
برنامه ازصفحه نمايش شما خارج شود اجرا کنید هیچ فرمان استانداردی برای چاپ يك فايل بر روی پايانه ويدئويي که در يك زمان
دارای صفحه نمايش کامل است وجود ندارد ،اگر چه تقريبا ً هر سیستم يونیکس دارای يك نمونه از اين فرمان ميباشد .سیستم شما
ممکن است دارای فرمان makeيا pgباشد سیستم ما دارای فرماني است که pنامیده مي شود ،ما به شما اجراء آن را در فصل 6نشان خواهیم داد .همچون catفرمان prمحتوای تمام فايلهايي که در يك لیست،نام گذاری شدهاند را چاپ ميکند اما به شکل مناسبي برای
چاپگرهای سطری ،هر صفحه دارای 66سطر است ( 11اينچ) و نیز دارای تاريخ و زماني است که آن فايل تغییر يافته است ،شماره
صفحه و نام فايل در بالی هرصفحه و تعدادی سطر اضافي به منظور رد کردن تاخوردگي در کاغذ از جمله ديگر امکانات اين فايل است .بنابراين junkرا به صورت مرتب چاپ کرده و سپس به بالی صفحه جديد رفته و Tempرا به صورت مرتب چاپ کنید:
$ pr junk Temp
محیط برنامه سازی لینوکس
16/322
Junk page 1
prنیز ميتواند خروجیهای چند ستوني بوجود آورد:
Sep 26 16:25 1983 To be or not To be
()60 more blank lines Sep 26 16:26 1983 Temp page 1 That is the question ()60 more blank lines $
$ pr- 3 filename هر فايل را در طرحهای سه ستوني چاپ کنید .ميتوانید هر تعداد مورد قبول را در محل " " 3به کار ببريد و prاين کار را به بهترين
نحو انجام ميدهد .کلمهـ filenameمکان مشخصي برای لیست نامهای فايلها ميباشد) pr-mمجمومهای از فايلها را در ستونهای
موازی چاپ ميکندpr)1( .را مورد مطالعه قرار دهید .اين نکته بايد مورد توجه قرار گیرد که prيك برنامه قالببندی به معنای حقیقي
تنظیم سطرها و فاصلهبندی حاشیهها نميباشد برنامه قالببندی صحیح nroffو Troffاست که در فصل 9مورد بحث قرار ميگیرد.
همچنین فرامیني وجود دارد که فايلها را با سرعت بالی چاپگر ،چاپ ميکند .به فهرست مورد نظرتان تحت نامهايي شبیه pr , Lp 1
نگاه کنید يا " چاپگر" را در فهرست جابجا شده مورد جستجو قرار دهید ،آنچیزی که بايد مورد استفاده قرار گیرد به تجهیزاتي بستگي
دارد که به ماشین شما ( سیستم) متصل است pr .او prغالباً به صورت توأم مورد استفاده قرار ميگیرد پس از اينکه prاطلعات را به
صورت کامل فرمت کرد pr 1 ،مکانیسم گرفتن آنها را از چاپگر خطي ،کنترل ميکند. در مراحل بعدی به اين موضوع مي پردازيم.
انتقال ،كپي ،پاك كردن فايلهاmr,cp ,rm
اجازه دهيد به فرامين ديگري نيز بپردازيم .اولين موضوع اين است كه نام فايل را عوض كنيم نامگذاري جديد يك فايل به وسيله " انتقال" آن از يك نام به نام ديگر انجام ميپذيرد .مثل اين مورد: $
precious
junk
mv
اين مورد به اين معناست که فايلي که برای نامیدن junkبه کار رفته است ،اکنون تحت عنوان preciousميباشد و محتوای آنها تغییر نکرده است .اگر شما 1Sرا اکنون اجراکنید ،فهرست متفاوتي را خواهید ديد junk :ديگر وجود ندارد اما preciousموجود ميباشد.
$ 1s Precious Temp $ cat junk cat con,t open junk $ آگاه باشید که اگر فايلي را به فايل ديگری که از قبل وجود داشته است انتقال دهید فايل مورد نظر ،جايگزين ميشود .به منظور گرفتن کپي از فايل ( يعني داشتن دو نسخه از چیزی) از فرمان cpاستفاده کنید:
کپي دوتايي از perciousاز Percious.saveتهیه کنید.
$ cp 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
While these again have greater still, And greauer still , and so on. W poem 263 q $ اولین فرمان سطرها ،کلمات و کاراکترها را در يك يا تعداد بیشتری از فايلها ميشمرد و اين فرمان پس از نقش شمارش لغات تحت عنوان wcاز آن ياد ميشود
$ wc poem 8 46 263 poem $ يعني ،شعر 8سطر 46 ،لغت و 263کاراکتر دارد .تعريف " کلمه" بسیار ساده است هر رشته (رديفي ) از کاراکترها که حاوی جای خالي فاصله يا سطر جديد نباشد کلمه نامیده ميشود Wc .بیش از يك فايل برای شما ميشماردـ ( و کل آن را چاپ ميکند) و
همچنین هر کدام از شمارشها را در وصورتي که شما از آن بخواهید ،متوقف ميسازد wc)1( .را مورد مطالعه قرار دهید.
دومین فرامین grepنامیده ميشود و اين فرمان فايلها يا سطرهايي که يك الگو را هماهنگ ميسازد را جستجو مي کند (نام آن از
)g/reguler-expression/pفرمان edاقتباس ميشود که در بخش ضمیمه 1توضیح داده شده است) فر ض کنید شما ميخواهید به دنبال کلمه " " fleaدر شعر بگرديد:
$ grep fleas poem greu flead have little flead And little fleas have gesser fleas, Have gret fleas themselves , in turn, Have greater fleas to go on, $ grepبه دنبال سطرهايي ميگردد که با الگو مطابق نیستند ،البته زمانیکه انتخاب – vبه کار برده شود ( .اين انتخاب درس از فرمان
ويراستاری " " Vنامیده ميشود،ميتوانید در مورد آن به عنوان معکوس موضوع تطابق،فکر کنید).
$ grep - V fleas poem upon their backs To bile, em, and so an infinitum. While these again have greater still, And greater still , and so on. $ grepميتواند برای جستجوی چندين فايل مورد استفاده قرار گیرد ،در اين صورت ،اين فرمان نام فايل را در هر سطری که با آن
هماهنگ است به پیشوند ميآورد بنابراين شما مي توانید تشخیص دهید که اين هماهنگي و تطابق در کجا اتفاق افتاده است .همچنین
انتخابهای برای شمارش ،تعداد و از اين قبیل موارد ،وجود دارد grepهمچنین تعداد زيادی از الگوهای پیچیده را تحت کنترل در
ميآورد تا اينکه تنها يك کلمه مثل " "fleasرا کنترل کند اما ما نظرمان را در مورد آن تا رسیدن به فصل 4به تأخیر مي اندازيم.
سومین فرمان sortاست که وروديهای درون خودرا به ترتیب الفبا سطر به سطر طبقهبندی ميکند .اين موضوع برای شعر چندان جالب نیست،اما اجازه دهید که اينکار را به صورت ديگری انجام دهیم و فقط ببینید که اين مورد شبیه به چیست:
$ sort poem and greater sTill, and so on.
محیط برنامه سازی لینوکس
19/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
طبقه بندی به ترتیب عددی
طبقه بندی به ترتیب عددی معکوس
Fold upperو حروف کوچك با هم ديگر شروع طبقه بندی در میدان
Sort - n Sort - nr Sort-f Sort +n
n+1-st
فصل 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
$ cat Newpoem Great fleas have little fleas Upen their back to bite them, And little fleas have greater fleas, and so on 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. $ تفاوت چنداني بین دو فايل وجود ندادر،در حقیقت ،شما برای پیدا کردن آن بايد سخت به دنبال آن بگرديد ،اين همان فرامین مقايسه فايلها است که يك فرمان مناسب و کاربردی است cmp .اولین جايي را که دو فايل از يکديگر متفاوت هستند را پیدا ميکند:
$ cmp poem new-poem Poem new-poem differ : char 58, line 2
اين فرمان ميگويد که اين فايلها در سطر دوم از يکديگر متفاوتند که اين مورد کامل صحیح است .اما اين فرمان نميگويد که تفاوت
در چیست و علوه بر اين هیچ گونه از تفاوتهايي را که وجود دارد مشخص نميکند يکي ديگر از فرامین مقايسه فايلها فرمان 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خلصهای از فرامیني است که ما تاکنون در ارتباط با فايلها از آنها صحبت کردهايم.
3ـ 1اطلعات بيشتري در مورد فايلها فهرست راهنما سیستم فايل شما را که تحت عنوانـ junkاست ازفايل فرد ديگری که به همین نام است،متمايز ميشناسد .اين تمايز به وسیله
محیط برنامه سازی لینوکس
21/322
گروهبندی فايلها به فهرستها ،صورت ميپذيرد که اين فرآيند نسبتاً به ترتیبي است که کتابها در کتابخانهها بر روی قفسهها جای داده مي
شوند ،بنابراين فايلهايي که در فهرستهای متفاوت هستند ميتوانند بدون هیچ گونه تضادی دارای يك نام باشند .به طور کلي هر کاربر
دارای يك فهرست شخصي و خصوصي است ،بعضي اوقات تحت عنوان فهرست loginاز آن ياد ميشود ،که تنها حاوی فايلهايي
است که متعلق به آن فرد است .زماني که شما با سیستم ارتباط برقرار ميکنید ،در واقع شما در فهرست شخصي خودتان هستید.
ممکن است فهرستي را که شما در حال کارکردن در آن هستید را تغییر دهید غالباً فهرست کنوني و آن فهرستي را که در حال فعالیت بر
روی آن هستید را مشخص کنید اما در اين شرايط فهرست شخصي شما هنوز به همان صورت قبلي باقي است .مگر اينکه شما عمل خاصي را انجام دهید مثلً زمانیکه يك فايل جديد ايجاد کنید در واقع اين فايل وارد فهرست کنوني شما ميشود از آنجايي که اين فايل
به عنوان فهرست شخصي شما است ،در واقع اين فايل به فايلي با همان نام که ممکن است در فهرست شخص ديگری باشد ،در واقع اين فايل به فايلي با همان نام که ممکن است در فهرست شخص ديگری باشد ،مربوط نميشود .فهرست ميتواند حاوی فهرستهای ديگر و نیز افیلهای معمولي باشد (فهرستهای بزرگ دارای فهرستهای کوچکتر هستند).
روش معمول برای به تصوير کشیدن اين سازماندهي شبیه به درختي از فهرستها و فايلها است .اين امکان وجود دارد که پیرامون هر کدام از اين درختها حرکت کرده و هر کدام از اين فايلهای درون سیستم را به وسیله شروع مسیر از ريشه درخت و حرکت به دنبال
شاخههای مناسب ،پیداکنیم .بر عکس شما ميتوانید از جايي که در آن قرار گرفتهايد شروع کرده و به سمت ريشه حرکت کنید .اجازه دهید که مورد اخیر را اول انجام دهیم .ابزار اصلي ما فرمان pwdاست( فهرست فعالیت چاپ) که نام فهرستهايي را که شما اکنون در
آنها هستید را چاپ ميکند:
محیط برنامه سازی لینوکس
22/322
جدول 1-1فرمانهای رايج فايل سیستم
نامهايتتت تتتتمامتتت تتتفايلهايتتت تتتموجودتتت تتتدرتتت تتتفهرستتتتتتت (دايركتوري)
راتتت تتتفهرستتتت تتتميكند
s-1
تنهاتتتتتتت تتتتتتتفايلهايتتتتتتت تتتتتتتنامگذاريتتتتتتت تتتتتتتتشدهتتتتتتت تتتتتتتتراتتتتتتت تتتتتتتفهرستتتتتتتت تتتتتتتميكند
1s filenames
بهت تتترتيب ت تتزمانيت تتفهرستت تتميكند،ت تتآنهايي ت تتكهت تتاخيراً تتبوجود ت تتآمدهت تتدرت تتابتدا ت تتقرارت تتگرفتهاند 1s-t
ليستيتتتت تتتتطويلتتتت تتتتوتتتت تتتتشاملتتتت تتتتاطلعاتتتتت تتتتزيادتتتت تتتتوتتتت تتتتنيزتتتتتتتت 1s-1tميتتتت تتتتباشد 1s-1
برتت تتاساستت تتآخرينتت تتزمانتت تتموردتت تتاستفادهتت تتقرارتت تتگرفتنتت تتفهرستتت تتميشودتت تتوتت تتنيزتت تتشامل 1s-u 1s-1u,1s-1utنيز ميباشد.
بهتتت تتتترتيبتتت تتتمعكوستتت تتتفهرستتتت تتتميشودتتت تتتوتتت تتتنيزتتت تتتشاملتتتتت rt,-rlt-وتتت تتتغيرهتتت تتتميباشد
1s-r
فايلهايتتتتتتتت تتتتتتتتنامتتتتتتتت تتتتتتتتگذاريتتتتتتتت تتتتتتتتشدهتتتتتتتت تتتتتتتتراتتتتتتتت تتتتتتتتويراستاريتتتتتتتت تتتتتتتتميكند ed - filename Fileرا به 2fileكپي كرده و در صورتي كه 1 file 2 file 2آن را جانويسي ميكند.
cp file
file2
فايلهاي نامگذاري شده را پاك كرده ،البته اين عمل
rm filename
به صورت تغییر ناپذير صورت ميگیرد
محتواهايتتتتتتت تتتتتتتفايلهايتتتتتتت تتتتتتتنامگذاريتتتتتتت تتتتتتتشدهتتتتتتت تتتتتتتراتتتتتتت تتتتتتتچاپتتتتتتت تتتتتتتميكند
cat filenames
محتواهاتتتتتتتتتتت تتتتتتتتتتتراتتتتتتتتتتت تتتتتتتتتتتباتتتتتتتتتتت تتتتتتتتتتتسرآمدتتتتتتتتتتت تتتتتتتتتتتچاپتتتتتتتتتتت تتتتتتتتتتتميكند pr filenames
66سطر را در هر صفحه
درتتتتتتتتتتتتتتتتتتتت تتتتتتتتتتتتتتتتتتتتستونهايتتتتتتتتتتتتتتتتتتتتتتتتتتتتتتتتتتتتتتت nچاپتتتتتتتتتتتتتتتتتتتت تتتتتتتتتتتتتتتتتتتتميكند
pr-n flienames
فايلهاي نامگذاري شده را در كنار هم چاپ ميكند
pr-m flie
names
(ستونهای چندگانه)
سطرها ،لغات و كاراكترها را براي هر فايل ميشمرد
wc
flienames
سطرهاتتتتتتتتتتت تتتتتتتتتتتراتتتتتتتتتتت تتتتتتتتتتتبرايتتتتتتتتتتت تتتتتتتتتتتهرتتتتتتتتتتت تتتتتتتتتتتفايلتتتتتتتتتتت تتتتتتتتتتتميشمارد wc-1 filenames
سطرهاي هماهنگ با الگو با چاپ ميكند
grep pattern
flienames
سطرهايي كه هماهنگ با الگو نباشد را چاپ ميكند
grep-v
pattern files
فايلها را به صورت الفبايي و به صورت سطري چاپ ميكند
sort
filenames
10سطرتتتتتتتتتتت تتتتتتتتتتتآخرتتتتتتتتتتت تتتتتتتتتتتفايلتتتتتتتتتتت تتتتتتتتتتتراتتتتتتتتتتت تتتتتتتتتتتچاپتتتتتتتتتتت تتتتتتتتتتتميكند tail filename nسطر آخر فايل را چاپ ميكند چاپ فايل را در سطر nشروع مي كند
filename Tail - n Tail +n filename
محیط برنامه سازی لینوکس
23/322
محل اولين تمايز را چاپ ميكند
filel filez
تمام تفاوتهاي موجود بين فايلها را چاپ ميكند. pwd $ usr/you/ $
cmp diff filel filez
اين فرمان ميگويد که شما در حال حاضر در فهرست خودتان و در دايرکتوری usrهستید که به نوبة خود اين فهرست در فهرست ريشه قرار دارد ،که اين فهرست به صورت قراردادی «م» نامیده ميشود .علمت /اجزاء نام را از يکديگر جدا ميکند؛ محدودة 14
کاراکتری که در بال ذکر شد برای هر جزء که چنین نامي حاوی فهرستهای تمام کاربردن سیستم است ( .حتي اگر فهرست اصلي شما به
صورت usr/you/نباشد ،در اين صورت pwdچیزی شبیه به آن را چاپ خواهد کرد و بنابراين شما بايد قادر باشید ،آنچه را که در زير اتفاق ميافتد ،پیگیری کنید) .اگر اکنون شما
$
1S/usr/youرا تايپ کنید ،دقیقا ً همان فهرست نامهای فايلي را دريافت ميکنید که شبیه به آنچه ميباشد که از 1Sمعمولي
دريافت کردهايد .زمانیکه هیچ شناسهای فراهم نباشد و 1Sمحتواهای فهرستهای معمول را فهرست ميکند ،و نام دايرکتوريها را نشان
مي دهد و محتوای آن دايرکتوری را فهرست ميکند .سپس برای اجرای $
1S/usrتلش کنید ،اين فرمان بايد يك سری طويلي از
نامها را چاپ کنید که در بین آنها دايرکتوری متعلق به شما نیز وجود دارد .مرحلة بعدی تلش برای فهرست کردن خود ريشه است .در
اين وضعیت جوابي شبیه به اين نمونه دريافت ميکنید:
$
/ 1S bin boot dev etc lib tmp unix usr $
(در مورد دو معناي /:دچار سردرگمي نشويد ،اين دو معنا ،نام ريشه بوده و در نامهاي فايها نقش جداكننده دارد) .اغلب اينها فهرستها هستند ،اما یونيکس فايلي است كه حاوي شكل قابل اجراء هستة اصلي یونيکس است .اطلعات بيشتر پيرامون اين موضوع در فصل 2آورده شده است .اكنون فرمان $ (اگر junkهنوز در فهرست شما وجود دارد).
cat / usr/usr/you/junkرا انجام دهيد.
محیط برنامه سازی لینوکس
24/322
نامت usr/you/junk/تحت تعنوانت ( path nameنام تمسير) فايل تنام تدارد Pathnam .داراي تمعناي مستقيم است ،و نام كامل مسير را از ريشهت (در سرتاسر درخت دايركتوري) به فايل خاص ،تنشان تميدهدت .اين تموضوع ،تقانون تكلي تدرت تسيستم تیونيکس تاست تكهت تشما ميتوانيد تازت تنام تفايل تمعمولي تيا تاز تنام تمسير تاستفاده تكنيد .فايل تسيستم تشبيه تبه شجرهت تنامت تشكل تگرفته تاست :درت تاينجات تتصويري توجود تدارد تكهت تاين تموضوع ترات تشفافتر ميسازد. Boot
bin
unix
tmp mary
data
junk
usr paul
etc mike
temp
Dev Jou
junk
Junk
فايل شما که 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
23 : 29 : 32 EDT 1983 22:20 22:40 23:04
26 26 26
26 sep sep sep
Mon sep bin/who / $ Srm tty/ Crw ttJ4 you tty5 $
تمرين 3ـ S/usr/games / $ :1را اجراء كنيد . و هر آنچه را که به طور طبیعي پیش ميآيد را انجام دهید .اين اتفاقات ممکن است خارج از زمان کاری طبیعي ،سرگرم کنندهتر به نظر
برسد.
تغيير دادن دايركتوري ـ 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
تمام آنها به همراه خود دايرکتوری شما را به دايرکتوری اصلي برميگرداند ،يعني همان دايرکتوری که شما با آن مرتبط هستید .زمانیکه کتاب شما چاپ شد ،ميتوانید آن فايلها را پاك کنید .به منظور پاك کردن دايرکتوری کتاب ،تمام فايلها موجود در آن را حذف کنید
(روش سريعتر و کوتاهتر را به شما خواهیم آموخت) ،سپس فرمان cdرا در دايرکتوری اصلي کتاب اجراء کرده و $
rmdir book
را تايپ کنید rmdir ،تنها دايرکتوری خالي را حذف خواهد کرد.
4 ت Shell 1 زمانیکه سیستم پیغام $را چاپ کرد و شما فرامیني را تايپ کرديد که اجراء شوند .اين هسته اصلي ( )kernelنیست که با شما مرتبط ميشود بلکه go-between ،فرمان تعبیر و تفسیر ياـ Shellرا فراخواني ميکند Shell .تنها يك برنامة معمولي شبیهـ dateياـ who
است ،اگر اين برنامه ميتواند کارهای قابل توجهي انجام دهد .اين حقیقت که Shellبین شما و امکانات هسته اصلي ( )Kernelجای گرفته است ،واقعیت دارد ،ما در مورد برخي از موارد آن در اينجا صحبت خواهیم کرد .سه نکته اصلي وجود دارد:
• مختصرت تنويسي تنامت تفايلها :ميتوانيدت تمجموعةت تكامليت تازت تنامهايت تفايلهات ترات تبهت تعنوان شناسه در برنامهاي به وسيلة خصوصي سازي الگويي براي نامها ،بدست آوريدShell ، نامهاي فايلهايي را پيدا ميكند كه با الگوي شما هماهنگي دارد. • تغيير مسير ورودي ت خروجي :ميتوانيد خروجي هر برنامه را به جاي رفتن به پايانه، طوري تنظيم كنيد كه به فايل وارد شود و در مورد ورودي طوري ترتيب دهيد كه ورودي به جاي تپايانه تازت تفايل تنشأت تگيرد .ورودي توت تخروجي تحتي تميتوانند تبه تديگربرنامهها تنيز متصل شوند.
• خصوصي سازي محيط :ميتوانيد فرامين شخصيتا و مختصر نويسي را بدين وسيله تشريح كنيد.
محیط برنامه سازی لینوکس
27/322
مختصر نويسي نام فايل اجازه دهید با الگوهای نام فايلها شروع کنیم .فرض کنید در حال تايپ کردن سند بزرگي همچون کتاب هستید .از لحاظ منطقي اين
سند بايد به قطعات بسیار کوچك مثل فصل و شايد بخش تقسیم شود .اساساً چنین تقسیمبندی بايد صورت گیرد ،اين فرايند به منظور
ويراستاری فايلهای بزرگ امری دشوار است .بنابراين ،بايد آن سند را به صورت تعداد فايلها تايپ کنید .ممکن است فايلها را برای هر
فصل جدا کنید و آنها را فصل ،1فصل 2و … نامگذاری کنید .يا در صورتیکه هر فصل به بخشهايي تقسیم شود ،ممکن است فايلهايي
ايجاد کنید که
فصل 2 .1
فصل 1 .1
فصل 2 .1
فصل 1 .2 فصل 1 .3
………
نام داشته باشد که اين عمل سازماندهي خاصي است که ما برای اين کتاب استفاده کردهايم .به کمك يك سیستم نامگذاری قراردادی
ميتوانید با يك نگاه اجمالي تعیین کنید که يك فايل خاص در کدام محل با کل فايلها تناسب پیدا ميکند .چه بخشهايي از کل کتاب را ميخواهید چاپ کنید؟ در اين مورد ميتوانید بگوئید :
$
ch 1.3
ch 1.1 ch 1.2
…… pr
اما به زودی از تايپ کردن نامهای فايلها خسته شده و شروع به غلط نوشتن ميکنید .اين جا همان مرحلهايي است که مختصر نويسي نام فايلها وارد عمل ميشود .درصورتي که بگوئید *pr ch $
Shellعلمت * رابه معنای ‘هر رديفي از کاراکترها’ تلقي ميکند ،بنابراين *chالگويي است که تمام نامهای فايلها را که در دايرکتوری
فعلي همراه chهستند را هماهنگ ميکند Shell .لیستي فراهم ميآورد که به ترتیب الفايي است و لیست را به prانتقال ميدهد .فرمان
prهرگز علمت * را نميبیند ،الگوهايي که Shellرا هماهنگ کردهاند در دايرکتوری فعلي لیستي از رديفهای کاراکتری را بوجود
ميآورند که به prانتقال داده ميشود .مرحلة بحراني ،عبارتست از مرحلهايي که مختصر نويسي نام فايلها خصوصیت فرمان prنباشد،
اما کار برنامة Shellباشد .بنابراين ميتوانید از آن برای تولید توالي نامهای فايلها برای هر فرمان استفاده کنید .برای مثال ،برای شمردن کلمات در اولین فصل:
chl.0 chl.1 chl.2 chl.3 chl.4 chl.5 chl.6 ToTal
3200 22435 22756 8481 28841 2030 2030 کل) 3801
*ch.1. 562 4081 4191 1561 5298 194 323 16210
$ wc 113 935 974 378 1293 33 75 )88933
برنامهای به نام echoوجود دارد که برای بررسي معنای کاراکترهای مختصرنويسي بسیار مفید است .همانطور که حدس ميزنیدecho ،
چیزی به غیر از انعکاس شناسههايش انجام نميدهد:
world
hello world
$ echo hello $
محیط برنامه سازی لینوکس
28/322
اما شناسهها ميتوانند به وسیله تطابق الگويي ،گسترش يابند: تمام نامهای ،کلیة فايلهای موجود در فصل 1را فهرست کنید. تمام نامهای فايلهای موجود در دايرکتوری فعلي را به ترتیب حروف الفبايي فهرست کنید.
*echo ch1
$
* echo
$
* $ pr
تمام فايلهای خودتان (به ترتیب حروف الفبايي) را چاپ کنید ،و
* $ rm تمام فايلهای موجود در دايرکتوری فعلي خود را پاك کنید( .بهتر است که از آنچه که ميخواهید بگوئید ،مطمئن شويد!) .علمت * به آخرين وضعیت در نام فايلها محدود نميشود ـ * ’Sهرجايي ميتواند باشد و چندين بار نیز ميتواند ،اتفاق افتد .بنابراين $
rm
* saveتمام فايلها را که با saveپايان مييابد را پاك ميکند .توجه داشته باشید که نامهای فايلها به ترتیب الفايي طبقه بندی شدهاند،
که اين طبقه بندی همانند ترتیب عددی نیست .اگر کتابتان دارای 10فصل است ،ترتیب آن ممکن است آنچیزی که موردنظر شما
است ،نباشد ،از اين رو فصل 10قبل از فصل 2قرار ميگیرد:
$
* echo
Ch 1.1 ch1.2... ch10.1 ch10.2 ...ch2.1 ch2.2... $ علمت * تنها خصوصیت تطابق الگو نیست که به وسیلة Shellفراهم ميشود ،اگرچه اين علمت به میزان زيادی مورد استفاده قرار مي گیرد .الگوی [ ]...هرکدام اگر کاراکترهای موجود در براکت را هماهنگ ميسازد .محدودهايي از حروف متوالي يا ارقام ميتوانند به
صورت مختصر نوشته شوند.
* [pr ch ]1 2 3 4 6 7 8 9
فصلهای 9و 8و 7و 6و 4و 3و 2و 1به غیر از 5را چاپ کن همین عمل را انجام بده
$
* ]pr ch ]1-46-9 $
Tempz, Tempكه ]rm Temp ]a-z $
هركدام از موجود است را پاك کن
الگوی ؟ هرگونه کاراکتر تنها (مجزا) را مطابقت ميدهد:
فايلها را با نامهای مجزای کاراکترها فهرست کن
$
فصل 1ـ ، 1فصل 1ـ ، 2فصل 1ـ 3و…
$
ch? .1
? 1S 1S-1
را فهرست کن اما فصل 1ـ 10را فهرست نکن
فايلهای ...Temp 1 ، Tempaو غیره را پاك کن
$
?rm Temp
توجه داشته باشید که الگوها تنها نامهای فايلهای موجود را تطبیق ميدهند .به ويژه شما نميتوانید نامهای فايلهای جديد را با استفاده از الگوها ،تنظیم کنید .برای مثال ،اگر بخواهید chرا هر نام فايل به chapterگسترش دهید ،نميتوانید اين کار را به اين نحو انجام دهید: عملي نیست!
$
ch.* chapter
*.mv
زيرا * chapter .هیچ نام فايل موجودی را تطبیق نميدهد کاراکترهای الگو شبیه * ميتوانید در نامهای مسیر و نیز نامهای فايلها ساده
استفاده شوند و اين تطابق برای هر جزء مسیر که حاوی کاراکتر خاص باشد صورت ميپذيرد .بنابراين */usr/Mary/اين تطابق را در
محیط برنامه سازی لینوکس
29/322
usr/mary/انجام ميدهد و usr/*/calendar/لیست نامهای فايلها تمام کاربران فايلهای calendarرا توسعه ميدهد.
درصورتي که بخواهید برای همیشه معنای خاص * ،؟ و غیره را استفاده نکنید ،در اين صورت کل شناسه را در علمت نقل قول ،
همانند
? 1S $ قراردهید .همچنین ميتوانید ،کاراکتر خاصي را با backslashدر تقدم قرار دهید
? \ 1s $ (به خاطر داشته باشید ،از آنجايي که؟ علمت از بین بردن سطر يا پاك کن نیست ،اين backslashبه وسیلة shellتعبیر و تفسیر ميشود نه بوسیلة هسته اصلي « .) »kerndنقل قول به طور مفصل در فصل ،3بحث شده است.
تمرين 4ـ )1تفاوتهای موجود بین اين فرامین چیست؟
$ echo junk $ echo / $ echo * $ echo * $ echo
$ 1S junk $ 1S / $ 1S $ 1S * $ 1S
تغيير جهت ورودي ـ خروجي اغلب فرمانهايي که ما تاکنون ديدهايم خروجي را در پايان بوجود ميآورند و برخي نیز مانند ويراستار ،ورودی آنها از پايانه نشأت گرفته است .اين امر تقريبا ً کلي است که پايانه بتواند به وسیله فايل برای ورودی و خروجي به صورت دوتايي يا برای هکردام به صورت مجزا جايگزين شود .به عنوان مثال:
$
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است که خودش هم در شمارش محسوب مي شود .ميتوانید نامهای فايلها را در ستونهای
درختي شکل با
چاپ کنید .و ميتوانید بینید که کاربر ويژهايي به وسیله ترکیب whoو grepارتباط برقرار کرده است
IS > temp pr – 3 < temp
$ $
$ 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 $
در بخش بعدی ،ما خواهیم ديد که اين اصل چگونه مورد استفاده قرار ميگیرد. تمرين 6ـ ، 1خروجي از $
Temp > Temp
درصورتي که نام فرمان را غلط نوشته باشید ،همانند $
WCرا شرح دهید.
who > Tempچه اتفاقي ميافتد؟
تمام مثالها در پايان بخش قبلي بر روی يك راهکار تکیه دارد :خروجي يك برنامه را د ورودی برنامة ديگری از طريق يك فايل موقتي
قرار دهید .اما فايل موقتي هیچ هدف ديگری ندارد ،به راستي اين فايل به منظور مورد استفاده قرار گرفتن چنین فايلي نامناسب است.
اين نتیجه منجر به يکي از بخشهای اصلي سیستم يونیکس که همان لوله است ميشود .لوله روشي است برای اتصال خروجي يك برنامه به ورودی برنامة ديگر بدون هیچ فايل موقتي؛ خط لوله عبارتست از اتصال دو يا تعداد بیشتر برنامه کاز طريق لولهها .اجازه دهید برخي از مثالهای پیشین را به منظور استفاده از لولهها به جای فايلهای موقتي ،مورد بررسي مجدد قرار دهیم .کاراکترهای ستونهای
عمودی به Shellاعلم ميکند که خط لوله را تنظیم کند : لیست فهرست بندی شده کاربران را چاپ کنید.
کاربران را شمارش کنید
لیست 3ستوني از نامهای فايلها
به دنبال کاربر ويژه جستجوکردن
who : sert $ who : wc-1 $ 1S : wc-1 $ 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
command,
output
options
Standard input Or files
Standard error
تقريباً تتمامت تفرمانهاييت تكهت تمات تتاكنونت تدرموردت تآنهات تصحبتت تكرديمت تبات تاينت تمدلت تسازگار ميباشند؛ت تتنهات تاستثناءت تدرت تفرمانهاييت تهمچون ت dateو ت whoاستت تكهت تهيچت توروديت ترا نميخوانند ،و به ميزان كمي شبيه cmpو ي diffاست كه دارد تعداد ثابتي از وروديهاي فايل هستند( .اما به انتخاب ‘ ‘-در اين موارد توجه كنيد).
تمرين 7ت )1تفاوت بين
$
who / sort who > sort $
را توضيح دهيد.
پردازش
Shellعلوه بر تنظيم لولهها چند كارايي ديگر نيز دارد .اجازه دهيد به طور خلصه بيشتر به جاي پرداختن به برنامهها به نوبت به اصول اجراي آنها بپردازيم ،چرا كه ما پيش از اين
محیط برنامه سازی لینوکس
33/322
تاحدودي به اين موضوع در ارتباط با لولهها پرداختيم براي مثال ،ميتوانيد دو برنامه را با يك فرمان به وسيله جدا كردن فرمانها با استفاده ا نقطه ويرگول ) ؛ت ) اجراء كنيد،ت Shell نقطه ويرگول ( ؛ ) را تشخيص داده و خط فرمان را به دو فرمان مجزا ميشكند: date ; who $ 1983
01:03:17
EDT
sep
27
Tue
00:43
27
sep
TTJo
Ten
23:45
26
sep
Tly 1
Dmr
23:59
26
sep
TTJ2
Rob
00:06
27
sep
TTJ3
Bwk
23:31
26
sep
TTJ4
Jj
23:04
sep 26
Tty5
You
23:34
sep 26
TTJ7
Ber
$ هر دو فرمانها (به ترتيب) قبل از اينكه sellبا يك كاراكتر پيغامي برگردد ،اجراء ميشوند.
شما نيز ميتوانيد به صورت همزمان درصورت تمايل بيش از يك برنامه اجراء كنيد .براي مثال :فرض كنيد مي خواهيد كار وقت گيري مثل شمردن لغات كتابتان را انجام دهيد ،اما نميخواهيد كه صبر كنيد تا WCقبل از اينكه شما مشغول كار ديگري شويد ،تمام شود. در اين صورت ميتوانيد بگوئيد: $ فرايند idبه وسيله shellچاپ ميشود.
& WC ch * > . out 6944 $
آمپرساند & در پايان خط فرمان به shellميگويد« :اجراي اين فرمان را شروع كن ،سپس فرمانهاي بيشتري را از پايانه سريعاً بگير» ،يعني منتظر تكميل آن نشو .بنابراين ،فرمان شروع خواهد شد ،اما شما درحاليكه اين فرمان در حال اجراء است ميتوانيد كار ديگري انجام دهيد .جهت گيري خروجي به فايل WC.outآن را از مداخله با هر آنچه كه شما در همان فرمان در حال انجام آن هستيد ،حفظ ميكند .نمونهاي از اجراي برنامه ،پردازش ناميده ميشود .اعدادي كه به وسيلة shellبراي فرمانها چاپ ميشود ،با & آغاز شد و
محیط برنامه سازی لینوکس
34/322
تحت عنوان process- idنام گرفت؛ ميتوانيد ا آن در فرمانهاي ديگري براي رجوع به برنامة در حال اجراي خاص ديگري استفاده كنيد .اين نكتة مهمي است كه بين برنامهها و پردازشها تمايز قائل شويم WC .يك برنامه است ،هر بار كه شما برنامة WCرا اجراء كنيد، اين برنامه پردازش جديدي ايجاد ميكند .اگر چندين نمونه از برنامههاي يكسان در يك زمانت تدرت تحالت تاجراءت تباشند،ت تهركدامت تبات process-idمتفاوتيت تبهت تصورتت تجداگانهت تپردازش ميشوند .درصورتي كه خط لوله با & شروع شود ،مثل $
& pr ch* |pr /695
precess-id of |pr $
پردازش در آن ،در يك زمان شروع ميشود ت & در تمام خطوط لوله بكار برده ميشود .تنها يك process-idپردازشهاي نهايي در تواليها ،چاپ ميشود .فرمان ت $
waitتا زماني صبر
ميكند كه تمام پردازشهاي آغازشده با & پايان پذيرد .درصورتي كه اين پردازش سريعًا باز نگردد ،به اين معناست كه شما هنوز فرمان در حال اجراء داريد .ميتوانيد فرمان waitرا با deleteقطع كنيد .ميتوانيد ازت precess-idكه بوسيله shellچاپ ميشود براي متوقف كردن فرايند پردازش آغاز شده با & ،استفاده كنيد: kill 6944 $
درصورتيكهت تشمات process-idرات تفراموشت تكنيد،ت تميتوانيدت تازت تفرمانت psبرايت تاطلعت تيافتن پيرامون هرآنچه كه شما در نظر داريد اجراء كنيد ،استفاده كنيد .اگر كار شما بينتيجه بود kill O ،تمام پردازشهاي شما را به غير از ارتباط شما با shellرا از بين ميبرد .اگر شما در مورد آنچه كه ديگر كاربران انجام ميدهند كنجكاو هستيد ps-ag ،به شما در مورد تمام پردازشهايي كه در حال اجراء است اطلعاتي ميدهد .در اينجا نمونههايي از خروجيها آورده شده است: $ CMD
TIMe
/etc/Cron 36 6423 0:02 6704
Tty 6:29
PID Co
5 Sh1
0:04
Sh -
ps - ag
محیط برنامه سازی لینوکس
35/322
6722
1
0:12 1
vi paper
4430
2
0:03
Sh -
6722
1
0:12
fi paper
4430
2
0:03
Sh-
6612
7
0:03
Sh-
6628
7
1:13
rogue
6843
2
0:02
write dmr
6949
4
0:01
login birnmler
6952
5
0:08
ch1.1 ch 1.2 ch 1.3 ch1.4
6951
5
0:03
1pr
6950
5
0:02
ps – ag
6844
1
0:02
reb
pr
write
$ PIDعبارتست ازت process-id ، TTJپايانهاي همراه با پردازش استت (همانندت who( ; TIME
عبارتست از پردازشگر زمان كه در دقايق و ثانيه ها به كار برده ميشود ،و مابقي فرماني است كه بايد اجراء شود PS .يكي از آن فرمانهايي است كه در انواع متفاوت سيستمها ، متفاوت است ،بنابراين خروجي شما ممكن نيست كه مانند اين مورد قالب بندي شود. درصورتيكه شناسهها ممكن است متفاوت باشند (در اين مورد به صفحه فهرست (Ps )1
مراجعه كنيد ).پردازشها تداراي تيك نوع طبقه تبندي ساختار سلسله تمانند تهستند كه فايلها نيز دارند .هر پردازش داراي مبداء بود و شايد داراي انشعاباتي نيز باشد .برنامة Shellسيستم شما با پردازشي همراه با هر آنچه كه شما به خط پايانة سيستم متصل كردهايد ،ايجاد ميشود .همان زماني كه شما فرمانها را اجراء ميكنيد ،آن پردازشها انشعابات برنامة Shellسيستم شما را كنترل و هدايت ميكنند .در صورتيكه شما يكي از برنامههايموجود تدرت تيكي تازت تآنت تپردازشها ترات تاجراءت تكنيد،ت تبراي تمثال تفرمانت 1بهت تمنظور رهايي از ،ed در اين صورت آن پردازش پردازش انشعاب متعلق به خودش كه انشعاب اصلي Shellاست را ايجاد ميكند .بعضي اوقات پردازش تا زماني طول ميكشد كه شما بخواهيد اجراء برنامهاي را شروع كنيد و سپس پايانه را خاموش كرده و بدون منتظر ماندن براي پايان
محیط برنامه سازی لینوکس
36/322
پذيري آن به خانه برويد.
اما اگر شما پايانهتان را خاموش كنيد يا ارتباط خود را قطع كنيد ،پردازش به طور طبيعي حتي اگر شما ازت & استفاده كنيد ،از بين ميرود .فرمانت ( nohupقطع نكردن) به منظور ارتباط با اين موقعيت ايجاد شده است:در صورتي شما اعلم كنيد ، & nohup command$ فرمان حتي اگر شما ارتباط خود را قطع كنيد ،تا زمان اجراء ادامه پيدا ميكند .هر گونه خروجي از فرمان در فايلي كهت nohup.outناميده ميشود ،ذخيره ميشود .هيچ روشي براي nohupبه منظور برگشت پذيري فرمان ،وجود ندارد .در صورتيكه پردازش شما تعداد زيادي از پردازشگرهاي منابع اصلي را شامل شود ،در واقع اين شرايط لطفي است در حق كساني كه باسيستم شما براي به جريان انداختن شغلتان با هزينه كمتري نسبت به قبل،شريك هستند،اين فرآيند به وسيله برنامة ديگري كه niceناميده ميشود ،انجام ميشود؛– & nice expencive command $
به طرز خودكار niceناميده ميشود،چرا كه اگر
شما در نظر داشته باشيد كه ارتباط خود را قطع نمائيد ،ميتوانيد براي داشتن فرماني كه كمي بيشتر طول بكشد ،از اين فرمان استفاده كنيد ،نهايتاً ،ميتوانيد به وضوح به سيستم بگوئيد كه پردازش را زمان صبح يعني كه افراد طبيعتاً در خواب به سر ميبرند، نه در محاسبه كردن ،شروع كند ،دين فرمان )at )1نام دارد. at tme $ Whaterer commands Jeu want Cti-d $ اين مورد كاربرد رايج است اما مسلمًا فرمانها ميتوانند از فايل نشأت بگيرند: at 3am < fle $ $
زمانها ميتوانند به سبكت 24ساعته نوشته شود ،شبيهت 2130و يا به سبكت 12ساعته . 630Pm مناسب كردن محيط
محیط برنامه سازی لینوکس
37/322
يكي از مزاياي سيستم یونيکس اين است كه چندي روش براي نزديك كردن آن به علقه شخصي شما يا قراردادهاي محيط محاسبة محلي شما ،دارد .براي مثال ما قبل از اين مسئلة استانداردهاي متفاوت را براي پاك كن يا كاراكترهاي از بين برندة سطرها كه با توجه به نقص عبارتند ازت
¿
توت @ ،ذكر كرديم .شما ميتوانيد هر زمان كه خواستيد اين
مورد را با فرمان erase , Kill K
$
STTJ
عوض كنيد ( ،تغيير دهيد) .در اين فرمان eشامل هر كاراكتري است كه شما براي پاك كن در نظر گرفتهايد و Kبراي كاراكتر از بين برندة سطرها در نظر گرفته شده است .اما تايپ نمودن اين فرمان هر زمان كه با سيستم مرتبط هستيد ،دردسرساز است Shell .در اين زمينه باعث رهايي از اين دردسر ميشود .اگر فايلي تحت عنوانت . profileدر دايركتوري ارتباط شما وجود داشته باشد Shell ،قبل از چاپ اولين پيغام فرمانها را در آن ،هنگامي كه شما ارتباط برقرار كردهايد ،اجراء ميكند .بنابراين ،شما ميتوانيد فرمانها را در . profileبه منظور تنظيم محيط پيرامونتان به همان صورت كه دوست داريد ،قرار دهيد و آنها (فرمانها) هر زمان كه شما ارتباط برقرار ميكنيد ،اجراء خواهند شد. اولين چيزي كه اغلب افراد در profileخود قرار ميدهند ،عبارتست از: erase
STTJ
درت تاينجات تمات تازت تاستفاده تميكنيم .بنابراين تميتوانيدت تآنت ترات تببينيدت تامات تميتوانيدت تكليد برگشت حروف به عقب ( )backspaceرا در . profileخود قرار دهيد STTy .نيز xرا براي xت CTL
ميفهمد ،بنابراين ،ميتوانيد همان اثر را با erase /h STTyدريافت كنيد .چرا كه cTL-hهمان backspaceاست( .كاراكترت تبهت تعنوانت تيكت تهمت تمعني تقديميت تبرايت تاپراتورت تلولهت ت تاست، بنابراين شما بايد از آن با علمت نقل قول محافظت كنيد) .درصورتيكه پايانة شما نقطة Tabحساس نداشته باشد ،ميتوانيد Tabsت را به خط STTyاضافه كنيد: erase ∧ h - Tabs
STTy
اگر علقهمند هستيد كه بفهميد اشغال بودن سيستم هنگامي كه با آن مرتبط هستيد چگونه تاست،ت who/wc - 1رات تاضافه تكنيد،ت تتات تاينكه تاينت تفرمان تتعداد تكاربران ترات تبشمارد.
درصورتيكه سرويس خبري وجود داشته باشد ،ميتوانيدت newsرا اضافه كنيد .بعضي از
محیط برنامه سازی لینوکس
38/322
مردم ،آدمهاي خوش شانس را دوست دارند ،بنابراين usr/games/fortune/
بعد از مدتي ممكن است متوجه شويد كه ارتباط برقرار كردن شما ،زنان زيادي وقت برده است (بيشتر طول كشيده است) .پس به اين منظور . profileخود را قطع كرده و درصورت لزومت تدوباره تارتباطت تبرقرارت تكنيد .برخي تازت تخصوصياتت Shellبوسيلة تمتغيرهايت Shellكنترل ميشوند ،البته با معيارهايي كه شما بتوانيد به آنها دسترسي پيدا كرده و سيستم خود را تنظيم كنيد. براي مثال ،رشته پيغامهايي كه ما به صورت $نشان دادهايم ،در متغيرهاي Shellكه ps1
ناميده ميشوند ذخيره ميشوند و شما ميتوانيد آن را در هرجايي كه دوست داريد تنظيم كنيد ،مثل اين مورد: ?Ps1= 1yes dear علمت نقل قول لزم است چراكه فضاهايي در رشته پيغامها وجود دارد.
فضاها پيرامون = در اين ساختار ،مجاز نميباشد Shell .همچنين متغيرهاي Hmoeو MaILرا مورد بررسي قرار ميدهد HOME .نام دايركتوري اصلي مشا است و اين دايركتوري به طور طبيعي بدون مجبور بودن به قرار گرفتن در profileتنظيم ميشود .متغيرها ، MaILنام فايلهاي استاندارد است يعني جايي كه نامههاي شما حفظ ميشود .درصورتي كه شما آن را براي Shellتعريف كنيد ،بعد از هر فرمان درصورتيكه نامة جديدي برسد به شما اطلع خواهد داد.
احتمالً تمفيدترين تمتغيرهايت Shellعبارتندت تازت تمتغيرهايي تكهت تجاهايي تكهت Shellبهت تدنبال فرمانها ميگردد را كنترل ميكنند .به خاطر داشته باشيد كه زمانيكه شما نام فرمان را تايپ تميكنيد،ت Shellبهت تطور تطبيعتي تاول تدر تدايركتوري تكنوني تبه تدنبال تآن تميگردد تو سپست تدرت bin/وت تبعدت تازت تآنت تدرت . usr/bin/اينت تتواليت تفهرستهات «مسيرت تجستجو» ناميده ميشوند و در متغير Shellكه PATHناميده ميشود ،ذخيره ميشود .اگر مسير جستجو آن مسيري نباشد كه شما ميخواهيد ،ميتوانيد آن را تغيير دهيد ،و معمولً در . profile 11ت ايتتن عمل در Shellبه نحو بدي انجام ميگيرد .پس از اينكه هر فرمان به صورت به بار سيستم افزوده شد، فايل را مورد بررسي قرار دهيد .همچنين ،درصورتيكه شما براي مدت طولني در حال كار كردن بر روي برنامه ويراستاري باشيد اطلعاتي در مورد نامه جديد فرا نخواهيد گرفت چرا كه شما فرمانهاي جديد را با ارتباط برقرارت كردن بات Shellاجراء نكردهايد .طرح و راهكار بهتر اين است كه هرچند دقيقه يكبار به جاي بعد از هر فرمان ،اوضاع را مورد بررسي قرار دهيد .فصل 7و 5نشان ميدهد كه اين نوع از مرورگرهاي نامه چگونه عمل ميكنند .سومين امكان كه براي هر فردي موجود نميباشد ،اين است كه تنها برنامة پست الكترونيكي خود شما را مطلع بسازد :اين شرايط مطمئناً زماني ميسر ميشود كه نامه تنها براي شما فرستاده شده باشد.
محیط برنامه سازی لینوکس
39/322
سيستمتان اين عمل انجام ميگيرد .براي مثال :اين سطر مسير را به سمت يك مسير استاندارد به علوة usr/games/تنظيم ميكند. one way
:/ bin ;/usr/bin : /usr/ games
...PATH:
اين فرآيند كمي عجيب به نظر ميرسد :توالي نام دايركتوريها به وسيله :از يكديگر جدا ميشوند .به خاطر داشته باشيد كه ‘ ’.همان دايركتوري فعلي است .شما ميتوانيد ‘ ’.را حذف كنيد و جزء صفر درت PATHبه معناي دايركتوري فعلي است .راه ديگر براي تنظيم مسير ( )PATHدر اين موردخاص عبارتستاز افزايش دادن معيار قبلي(PATH= $ PATH: /usr
) /games Anether wayميتوانيد مقدار هرگونه متغيرهاي Shellرا به وسيله پيشونددار كردن نام آن با ، $بدست آوريد .در مثال بال ،حالت PAHT $مقادير فعلي را اصلح ميكند ،به نحويت تكهت تبخشت تجديد،ت تافزودهت تميشودت توت تنتايجت تبه ت PATHبرگرداندهت تميشود .شما ميتوانيد اين فرايند را با echoاثبات كنيد: $
is $ PATH
echo PATH
PATH is :/bin:/usr/bini /usr/games $
$ HOME
echo
your legin directory/
usr/you
$
اگر شما برخي از فرمانهاي مربوط به خودتان را در اختيار داشته باشيد ،ممكن است بخواهيد آنها را در دايركتوري مربوط به خودتان جمعآوري كرده و آنها را به مسير جستجو شخصيتان اضافه نمائيد .در اين صورت PATH ،شما ممكن است چنين به نظر برسد: PATH= : $ HOME /bin:/bin:/usr/bin:/usr/games
ما در مورد نوشتن فرمانهاي شخصيتان در فصل 3خواهيم كرد .متغير ديگر كه غالباً به وسيله تزئينات ويراستاري متن استفاده ميشود تا به وسيله ، edعبارتست از TERMكه نام نوعي از پايانههايي است كه شما از آن استفاده ميكنيد .چنين اطلعاتي ممكن استت تاينت تامكانت ترات تبرايت تبرنامهت تهات تفراهمت تآوردت تكهت تصفحهت تنمايشت تشمات ترات تبهت تميزان كارآمدتري كنترل تكند .بنابراين ممكن است چيزي شبيه تبهت TERM = a dm3رات به فايل profileخودت تاضافهت تنمائيد .همچنينت تاينت تامكانت توجودت تداردت تكهت تازت تمتغيرهات تبرايت تاختصار نويسي استفاده شود .اگر مكررًا به برخي از دايركتوريها با نامهاي طولني مراجعه داشته
محیط برنامه سازی لینوکس
40/322
باشيد ،اين امر شايسته است كه سطري همچون d= /harribly / lony / dinectory / name به profileخود اضافه نمائید ،بنابراين ميتوانید موردی شبیه cd $ d $را داشته باشید .متغیرهای شخصي همچون dبه منظور
متمايز نمودن آنها از مواردی که با خود Shellمورد استفاده قرار ميگیرند همچون ، PATHبه صورت قراردادی با حروف کوچك
نوشته ميشوند .نهايتا ً ،لزم است به Shellاعلم کنید که در نظر داريد از متغیرها در ديگر برنامه ها استفاده کنید ،اين عمل با فرمان expartانجام مي پذيرد ،که در مورد اين موضوع در فصل 3بحث خواهیم کرد.
Exprot MAIL PATH TERM به منظور خلصه نمودن ،در اين مرحله فايل ، profileمعمولي وجود دارد که شبیه به اين مورد است: $ cat . profile STLy erase ∧h - Tabs MAIL = /usr/ spool/ mail / you PATH= $ HOME /bin : /bin: / usr/ bin:/usr/ games B=$ HOME / book Export MAIL PATH TERM b Date Who / WC-1 $ به هیچ وجه ما خدماتي را که Shellفراهم آورده است را ناديده نميگیريم .يکي از مفیدترين خدمات اين است که شما ميتوانید فرمانهای شخصي خودتان را به وسیله بسته بندی فرمانهای موجود در يك فايل به منظور پردازش شدن بوسیله shellايجاد کنید .اين
نکته قابل توجه است که تا چه اندازه اين امر ميتواند به وسیله اين مکانیسم ساده به نتیجه برسد .بحث ما در اين مورد از فصل 3
شروع ميشود.
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
فصل : 2سیستم فایل همه چیز در سیستم يونیکس به صورت يك فايل است .اين سیستم بسیار سادهتر از آن است که شما فکر ميکنید .زمانیکه اولین نسخه
اين سیستم طراحي ميشد ،قبل از آن که نامي داشته باشد ،بحثها بروی سیستم فايل متمرکز شد که برای استفاده ،تمیز و ساده باشد.
سیستم فايل مرکز موفقیت و سادگي سیستم يونیکس است .اين سیستم يکي از بهترين مثالهای فلسفه «سادهتر کنید» است؛ که نشان دهنده توان عملکرد پیاده سازی چند ايده درست انتخاب شده ميباشد.
برای راحتر صحبت کردن در مورد دستورات و روابط آنها نیاز به پیش زمینه مناسبي از ساختار و عملکرد بیروني فايل سیستم داريم.
اين فصل بسیاری از جزئیات استفاده از سیستم فايل را در بر دارد -فايل چیست ،چگونه بازنمايي ميشود ،شاخهها و سلسله مراتب فايل سیستم ،مجوزها(inode ،رکورد داخلي سیستم فايل) و فايلهای دستگاه جانبي.
چون بسیاری از کاربردهای يونیکس منجر به دستکاری فايلهاميشود ،فرمانها و دستورات زيادی برای فايل بررسي و تنظیم فايلها دارد؛ در اين فصل به برسي پرکاربردترين آنها پرداخته ميشود.
مباني فايلها يك فايل رشتهای از بايتها است( .بايت تکه کوچکي از اطلعات است ،که عموماً هشت بیت طول دارد .يك بايت را ميتوان معادل با
يك کاراکتر دانست ).سیستم هیچ ساختاری بر روی فايل و هیچ معنايي برای محتوای آن در نظر نميگیرد؛ مفهوم بايتها فقط به
برنامهايي که فايل را تفسیر ميکند ،بستگي دارد .علوه بر اين همانطور که خواهید ديد ،اين موضوع نه تنها در مورد فايلهای ذخیره
شده برروی ديسکت بلکه در مورد دستگاههای جانبي نیز صادق است .نوار مغناطیسي ،نامهها ،کاراکترهای تايپ شده روی صفحه کلید، خروجي به چاپگر خطي ،دادههای جاری برروی خط لوله ،تا جايي که به سیستم و برنامههای داخل آن مربوط باشد همگي فايل و
معادل رشتهای از بايتها ميباشند.
بهترين راه درك فايل بازی کردن با آنها است ،بنابراين با ايجاد يك فايل کوچك شروع ميکنیم:
$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
بدون اينکه نیاز به معرفي يك کاراکتر جديد برای اينکار باشد.
وقتي که يك برنامه از پايانه شما ميخواند هر خط ورودی وقتي که کارکتر newlineتايپ شده بوسیله هسته به برنامه داده ميشود.
بنابراين وقتي که ي ك اشتباه تايپي مرتکب ميشويد ميتوانید برگرديد و آن ر ا تصحیح کنید .البته اگر اشتباه ر ا قب ل ا ز فشار
Enterتشخیص دهید .بعد از آن خط توسط سیستم خوانده شده و شما نميتوانید آن را اصلح کنید.
با استفاده از برنامه catميتوان ورود اطلعات به صورت هر بار يك خط را مشاهده کرد .در بعضي از سیستمهای قديمي catبه طور
معمول برای افزايش کارايي خروجي خود را بافر ميکند .برای رفع اين مشکل از گزينه uميتوان استفاده کرد:
$cat -u 123 123 456 456 789 789 ctl-d $ زمانیکه returnرا فشار دهید catخط را دريافت ميکند؛ بدون بافر کردن اطلعات بلفاصله پس از دريافت آن را چاپ ميکند.
حال موارد متفاوت را امتحان كنيد؛ تعدادي كاراكتر و بعد از آن يك ctl-dبجای Enterتايپ كنيد: $ cat -u 123ctl-d123 Catکاراکترها را بلفاصله چاپ ميکند .تايپ ctl-dميگويد «کاراکترها بلفاصله بفرست؛ من برای برنامهای که از پايانه ميخواند تايپ کردهام».
برعکس Enterخود ctl-dبه برنامه فرستاده نميشود .حال دومين ctl-dرا بدون كاراكترهاي ديگر تايپ كنيد:
$ cat -u 123ctl-d123ctl-d$ شل با يك پیامواره پاسخ ميدهد؛ زيرا Catهیچ کاراکتری را نميخواند ،قطعا اين به معني پايان فايل است در نتیجه متوقف ميشود. ctl-dهر چیزی را که شما تايپ کردهايد به برنامهای که از پايانه ميخواند ميفرستد .اگر شما چیزی تايپ نکرده باشید ،بنابراين برنامه
هیچ کاراکتری را نميخواند و اين چیزی شبیه به انتهای فايل است .به همین دلیل تايپ کردن ctl-dشما را از سیستم خارج ميکند، زيرا شل ورودی ديگری نميبیند .البته ctl-dبرای مشخص کردن انتهای فايل استفاده ميشود .البته عملکرد عمومي بیشتری دارد.
در فایل چه چیزی هست؟ قالب بندی فايل به وسیله برنامههايي که از آن استفاده ميکنید معین ميشود؛ انواع فايلها شديدا متنوعند ،شايد به خاطر اينکه برنامهها
متنوعي وجود دارد .ولي تا زمانیکه نوع فايل توسط فايل سیستم مشخص نشود ،هسته نميتواند نوع فايل را مشخص کند؛ زيرا در مورد
آن چیزی نميداند .دستور fileيك حدس مناسب ارائه ميکند:
$ file /bin /bin/ed /usr/share/man/man1/ed.1.gz /bin: directory /bin/ed: ELF 32-bit LSB executable, Intel 80386, version 1 )SYSV(, for GNU/Linux
محیط برنامه سازی لینوکس
46/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
recips : directory $ IS re cipes cookie pie $ IS recipes / Pie apple crust \$ تصويري از يك سيستم فایل در زير نشان داده شده است. usr /you / recipics cookie choc.ship
junk pie
crust
apple
فرمان ( 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”( and
‘ dot-dot”( ’.
دايرکتری ،ريشه ( )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اطلعات مجوز را در میان ديگر چیزها چاپ ميکند.
IS – 1 / etc / passwd 30 10 :40
Aug
5115
1 root
- rw – r – r - -
IS – Ig / etc / passwd 1 adm
$
- rw – r - - r - -
$
محیط برنامه سازی لینوکس
51/322
اين دو خط ممکن است مجموع ًا اينگونه تفسیر شود 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 $ 6348 mar 29 1983 / bin / who -
1 root
rwxrwxv–w
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مالك فايل مجوز فايل را بدون توجه به مجوزها تغيير ميدهد .حتي اگر شخص ديگري شما را وادار كند كه فايل را بنويسيد ،سيستم به شما اجازه نميدهد كه بيتهاي مجوزش را تغيير دهيد. 704 sep 25
IS – Id / user / mary d r w x r w a r w x 5 mary 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
متفاوتي داشته باشد.
فرمان Inيك پیوند با فايل کنوني ميسازد$ .
Inold – file new file
هدف از پیوند ،دادن دو نام به يك فايل يکسان است .زيرا اغلب ميتواند به صورت دوايرکتری متفاوتي ظاهر شود .در بسیاری از
سیستمها پیوند با 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
$ rm link to junk total 2 -rw – rw – rw – 1 you drw x rw x rw x 4 you $ بعد از اينکه link to junkحذف شود ،شمار پیوندها به يك باز ميگرد همانطور که قبل نیز گفتیم عملیات rmبه روی فايل تنها پیوند را ميشکند .فايل تا وقتي که آخرين پیوند وجود داشته باشد حفظ ميشود .البته در عمل ،بسیاری از فايل ها تنها يك پیوند دارند.
اما ما دوباره شاهد نظريه سادهای هستیم که انعطاف پذيری بزرگي را فراهم ميکند.
پیوندی با فايل برقرار ميشود ،دادهها غیر قابل برگشتند .فايل حذف شده رو به نابودی و سوختن ميرود .و هیچ راهي برای بازگرداندن
آنها از خاکستر شدن نیست( .امید ضعیفي برای تجديد حیات وجود دارد ،بسیاری از سیستمهای يونیکس بزرگ دارای فرايند پشتیباني هستند که از تغییرات فايلها مانند نوار مغناطیسي کپي ميگیرند .از اين به بعد آنها ميتوانند قابل برگشت باشند .برای اطمینان خاطر
شما بايد بدانید که پشتیبان تا چه حد از سیستم شما حفاظت ميکند .اگر پشتیباني وجود نداشته باشد مشاهده ميکنیم که ديسك دچار خرابي بدی ميشود.
پیوند با فايل قابل دسترسي است ،وقتي دو نفر ميخواهند در يك فايل با هم سهیم باشند .اگر گاهي شما ميخواهید فايل ها را تفکیك کنید (يك فايل متفاوت با اطلعات يکسان) شما ميتوانید از مدارك کپي بگیريد قبل از آنکه تغییرات زيادی در آن ايجاد شود .برای
مثال شما ميتوانید اطلعات اصلي را بدون هیچ تغییری دوباره ذخیره کنید .ساختن پیوند کمکي نميکند ،زيرا وقتي د ادهها تغییر کند پیوندها نیز تغییر ميکنند CP .کپيهای فايل را تشکیل ميدهند.
$ cp junk copy of junk $ Is – Ii total 3 1 5 8 5 0 - rw – rw – rw- 1 you 15768 - rw – rw – rw – 1 you 15274 drw x rw x rw x 4 you $ i-numberبرای junkو copy of junkمتفاوت است .زيرا فايلهای متفاوتي هستند .حتي اگر دارای محتوای يکساني باشند .اغلب يك نظريه خوب به يك مجوز بر روی کپي پشتیبان تغییر مييابد ،بنابراين حذف کردن آن به طور تصادفي بسیار سخت است.
chmoe – w copy of junk
$ ⋮ ⋮
تغییر دادن کپيهای فايل و حذف آنها تغییری در اصل و مبدأ ايجاد نميکند .توجه داشته باشید که چون copy of junkنوشته است که مجوزها قطع شدهاند rm ،برای حذف فايل نیاز به تائید دارد.
برای اجرای عملیات فايلها ،بیش از يك فرمان وجود دارد،ـ mvفايلها را با مرتب کردن پیوندها دوباره نامگذاری ميکند.
دستورالعمل آن به صورت cpو Inاست.
$ mv junk sam old junk $ Is – Ii total 2 1 5 2 7 4 drw x rw x rw x 4 you 1 5 7 6 8 - rw – rw – rw - 1 you
محیط برنامه سازی لینوکس
57/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
$
$ $
mk dir sh cp / usr / src / end / sh * sh cpاز تمامي شل فايلهای منبع از دايرکتری فرعي shکپي برداری ميکند( .فرض ميکنیم ساختار دايرکتری فرعي به صورت usr / src / cnd / shنميباشد و cpنیز خیلي کارآمد نیست).
در بسیاری از سیستمها In ،بحثهای فايل چندگانه را ميپذيرد .همچنین در مورد دايرکتریها نیز همین گونه عمل ميکند .و در
بسیاری از سیستمها mvو cpو Inتنها به يك فايل مرتبط است که نام خود را برای اجرای عملیات امتحان ميکند.
6ـ 2ـ سلسله مراتب دايركتري bin در فصل اول نگاهي بر روی سلسله مراتب سیستم فايل انداختیم که از usr / you /شروع ميشود .اين بار قصد داريم در مورد آن با
يك روش برنامهريزی شده تحقیق و بررسي کنیم .که با بیش از سه ريشه ( )rootآغاز ميشود.
Is / boot dev etc lib tmp unix usr
$
$ /يونیکس برای خود هسته يونیکس يك برنامه است .وقتي سیستم شروع به کار ميکند unix /را از روی ديسك خوانده ميشود .اين فرايند در دو مرحله رخ ميدهد .ابتدا فايل boot /خوانده ميشود ،سپس از روی unix/ميخواند .اطلعات زيادی در مورد اين فرايند
سیستم خود راهانداز ممکن است در )boot )8يافت شود .بقیه فايل در اسلش دايرکتری است که هر کدام قسمتهای کاملي هستند که
محیط برنامه سازی لینوکس
58/322
مجموع سیستم فايل را به وجود ميآورند.
بیتها را در دايرکتری مذکور پیدا کنید .شما با طرح کلي سیستم فايل آشنايي زيادی داريد و ميتوانید از آن استفاده کنید .جدول 1ـ 2
فضاهای مناسبي را برای تماشا پیشنهاد کرده گرچه بسیاری از اسمها به سیستم وابسته است.
bin /را که قبل ديدهايم .آن يك دايرکتريست و جايي قرار ميگیرد که برنامههای اصلي نظیر whoو edقرار ميگیرند. )dev )devies /که در بخش بعدی در موردش بحث خواهیم کرد.
)etc )et ceterw /که آن را قبل ديدهايم که شامل فايلهای اداره کننده متعددی نظیر passwdو بسیاری از برنامههای سیستمي نظیر /
etc / gettyکه همانند ابتدای کار ارزش دارد و با bin/login /مرتبط است.
etc / rc /فايل فرمانهای شل است که بعد از سیستم خود راهانداز ،اجرا ميشود. etc / group /تعدادی از اين گروه را فهرستبندی کرده است.
libclibrar /شامل قسمتهايي از کامپايلر است .مانند lib / cpp /
tmp )temporaries0 /که مخزني برای فايلهای کوتاه مدت که در طول اجرای برنامه ساخته شده ،ميباشد .وقتي که شما ويراستار edرا راهاندازی ميکنید ،برای مثال ،او فايلي با نام tmp/e00512/ميسازد که تمامي کپيهای فايل را در بر دارد .در اين صورت شما
به جای اينکه با اصل فايل سروکار داشته باشید ،فايل را ويرايش کردهايد .البته اين فايل ميتوانست در دايرکتری جاری شما ساخته
شود ولي بهتر است که در tmp /قرار گیرد .گرچه ناخوشايند به نظر ميرسد .شما ممکن است فايلي به نام e 00512در دايرکتری
خود داشته باشید .وقتي سیستم شروع به کار ميکند tmp / ،به طور خودکار پاك ميشود .بنابراين اگر سیستم خراب شود،دايرکتری
شما يك فايل ناخواسته به دست نميآورد .اغلب tmp /بر روی ديسك مرتب ميشود تا سهل الوصول باشد.
در اين جا مشکلي وجود دارد که وقتي در tmp/برنامههای متعددی ساخته ميشود ممکن است آنها به فايلهای يکديگر رجوع کند.
به همین دلیل فايل موقت edنام ويژه ای دارد و تضمي ميشود که برنامه ديگری برای فايل موقت خود نام مشابه آن را انتخاب نکند. در فصل 5و 6چگونگي اين عمل را خواهیم ديد.
usr /سیستم فايل کاربر خوانده ميشود ،گرچه با کاربرهای اين سیستم کار زيادی نميتوان انجام داد .در ماشینهای ما ،دايرکتری ورودی usr / buk , / usr / rob / ،ميباشند .وقتي فايل شخصي شما در دايرکتری فرعي usr /قرار بگیرد ،چیزهای زيادی در آنجا
وجود دارد که شما دوست داريد آنها را پیدا کنید .در , /دايرکترهايي به نامهای usr / bin /و usr / lib /و usr / tmp /قرار دارد
که عملیاتي شبیه به نامهای خود را اجرا ميکنند و شامل برنامههايي هستند که کمتر برای سیستم بحران ايجاد ميکند .برای مثال nroff
در usr / bin /يافت ميشود و نه در bin /؛ مجموعه روال fortRanنیز در usr / lib /قرار دارد .چیزی که بايد دانست اين است که
بحرانها در سیستمهای مختلف ،متفاوتند .بعضي سیستمها مانند th Edition 7که گسترش يافته نیز هست ،تمامي برنامههای bin /را داراست و تمامي usr / bin/را لغو ميکند و از بین ميبرد .بقیه نیز به خاطر استفاده مکرر usr / bin /را به دو دايرکتری تقسیم
ميکند.
دايرکترهای ديگر در usr ، / usr / adm /ميباشند که شمارش اطلعات را شامل ميشوند.
usr / dic /که يك فرهنگ لغت معمولي را در بر دارد .راهنمای خط ـ وصل ،در usr / manنگهداری ميشود .برای مثال نگاهي
بیندازيد به
/ usr / man / man 1 / spen 1.
محیط برنامه سازی لینوکس
59/322
اگر سیستم شما ،خط ـ وصل منع کدرا داراست ،شما ميتوانید آن را در usr/src/پیدا کنید .صر وقت برای يافتن فايل جديد ارزش زيادی دارد به خصوص در مورد usr /که چگونگي سازمان يافتن يك فايل و در کجا قرار داشتن آن را نشان ميدهد.
7ـ 2ـ دستگاهها : ما قبلً گذری بر 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
date > / dev / tty wed sep 28 02 : 42 : 23
$
EDT 1983 $ وقتي که برنامهای به واکنش در مقابل کاربر نیاز دارد ميتوان از dev / tty /استفاده کرد حتي اگر ورودی و خروجي استاندارد آن با
فايلها در ارتباط باشد Crypt .اولین برنامهای است که از dev / tty/استفاده ميکند .يك متن واضح « » clear teatکه از ورودی
استاندارد وارد ميشود و دادههای رمزگذاری شده به خروجي استاندارد ميروند بنابراين cryptکلید رمز را از dev / tty /ميخواند.
$ crypt < c 1 ear text > crypted text Enter key : $ استفاده از dev / tty /در اين مثال صريح نیست ولي در آن وجود دارد .اگر cryptکلید را از ورودی استاندارد بخواند ،پس اولین خط متن پاك « »cleartextرا ميتواند بخواند .بنابراين به جای اينکه cryptرمز dev / tty /را باز کند ،کارکترهای خودکار را قطع ميکند و کلید رمز شما روی صفحه پديدار نميشود .در فصل 5و 6به اين مطلب بیشتر اشاره خاهیم کرد.
گاهي شما ميخواهید برنامهای را اجرا کنید ،اما اهمیتي نميدهید که از کدام ورودی استفاده ميکنید .برای مثال شما به اخبار امروز
نگاهي انداختهايد و ديگر نميخواهید آن را بخوانید .اگر فرمان newsرا به فايل dev / nu 11 /بدهید باعث ميشود خروجي آن حذف شود.
$ news > / dev / nu 11 $ دادههای نوشته شده در dev / nu 11 /بدون هیچ دستوری وقتي حذف ميشوند که برنامههای خوانده شده از dev / nu 11 /تمام
شود ،زيرا خواندن ، dev / nu 11 /بايتها را صفر ميکند.
استفاده رايج از dev / nu 11 /حذف کردن يك خروجي عاديست .بنابراين پس از آن پیغام خطاشناسي پديدار ميشود .برای مثال فرمان timeکاربرد cpuرا برای يك برنامه بیان ميکند .اطلعات بر روی خطای استاندارد تايپ ميشود.
$
Is – 1 / usr / dict / words -r--r --r--1 bin $ time grep e / usr / dict / words > / dev / nu 11 real 8.0 user 3.9 sys 2.8 $
اعداد در خروجي زمان ،سپری شدن زمان را نشان ميدهند و زمان cpuدر برنامه سپری ميشود و هنگامي که برنامه در جريان است
زمان cpuدر هسته سپری ميشود.
Egrepگونه قدرتمندی از grepميباشد که در بخش 4در موردش بحث خواهیم کرد و هنگام جستجوی يك فايل بزرگ سرعتش دو
برابر grepميشود .اگر فرم خروجي grepو egrepبه
dev / nu 11 /فرستاده نشد ما ميتوانیم منتظر صدها هزار کارکتری باشیم که ظاهر ميشوند روی پايانه قبل از يافتن اطلعات زمان.
محیط برنامه سازی لینوکس
62/322
فصل :۳استفاده از شل شل ـ برنامهای که درخواستهای شما را برای اجرای برنامهها تفسیر ميکند ـ مهمترين برنامه برای اکثر استفادهکنندگان از يونیکس
ميباشند؛ با استثنای ممکن از ويراستار متن مورد علقه خود ،شما زمان بیشتری را درخصوص کار با شل نسبت به هر برنامه ديگری
سپری ميکنید .در اين فصل و در فصل ،۵ما زمان قابل توجهي را به تواناييهای شل اختصاص ميدهیم .نکته مهمي که ما ميخواهیم نشان دهیم اين است که شما ميتوانید عملکردهای زيادی را بدون کار خیلي سخت و مطمئناًـ بدون ذخیره کردن مجدد برای برنامهنويسي در يك زبان قراردادی مانند Cانجام دهید ،اگر شما بدانید که چگونه از شل استفاده کنید.
ما شمول خود درخصوص شل را به دو فصل تقسیم کردهايم .اين فصل يك مرحله را فراتر از ضرورتهای ارائه شده در فصل ۱برای برخي از ويژگیهای تصوری شل اما عموما ً استفاده شده ،بیان ميکند .مانند فراکاراکترها ،نقل قول کردن ،ايجاد فرمانهای جديد ،عبور
آرگومانها درون آنها ،استفاده از متغیرهای شل و برخي از روند کنترل اولیه .موضوعاتي وجود دارند که شما بايد برای استفاده خود از
شل بدانید .اطلعات موجود در فصل ،۵عمیقتر بیان ميشوند ـ اين فصل برای نوشتن برنامههای مهم شل اختصاص دارد ،برنامههايي که برای استفاده توسط ديگران ضد گلوله ميباشند .تقسیم بین دو فصل تا اندازهای اختیاری ميباشد ،البته هر دو فصل نهايتاً بايد مطالعه
شوند.
۳.۱ساختار سطر فرمان در ادامه ،ما نیاز به اندکي درك بهتر در اين خصوص داريم که يك فرمان چیست و چگونه توسط مثل تفسیر ميشود .اين بخش يك
شمول رسميتر ،با اندکي اطلعات جديد از مبنای شل معرفي شده در فصل اول ميباشد.
ل نامیدن يك فايل برای اجرا ميباشد (بعداً ما انواع ديگری از فرمانها را خواهیم ديد) : سادهترين فرمان ،تنها يك کلمه است که معمو ً اجرای فايل /bin/Who
۰۷:۵۱ ۰۸:۳۲
۲۸
sep
tty ۲
$who You
۲۸
sep
tty ۴
jpl $
يك فرمان معمولً با يك سطر جديد پايان ميپذيرد ،اما يك سمي کالن ؛ نیز يك پاياننمای فرمان ميباشد : ۱۹۸۳ ۱۹۸۳
EDT
۰۹:۰۷:۱۵
; $ date web sep ۲۸
$ date ; who web sep ۲۸ ۰۹۷:۲۳ EDT
you tty ۲ sep ۲۸ ۰۷:۵۱ jpl tty ۴ sep ۲۸ ۰۸:۳۲ $ اگر چه سمي کالنها ميتوانند برای پايان دادن به فرمانها استفاده شوند ،اما معمولً تا زماني که شما RE TV RNرا تايپ نکنید هیچ
اتفاقي نميافتد .توجه داشته باشید که شل فقط يك پیامواره را پس از فرمانهای متعدد چاپ ميکند ،اما به جز برای پیامواره ،
محیط برنامه سازی لینوکس
63/322
$ date ; who برابر با تايپ دو فرمان بر روی سطرهای متفاوت ميباشد .بويژه who ،اجرا نميشود تا زماني که dateپايان يافته باشد.
ارسال خروجي« » date ; whoرا درون يك لوله ،بررسي کنید :
$ date ; who | wc wed sep ۲۸ ۰۹:۰۸:۴۸ EDT
۱۹۸۳ ۶۰
۲
۱۰
$ اين نبايد چیزی باشد که شما انتظار داشتید ،چون فقط خروجي ، whoوارد wcميشود .اتصال whoو wcبا يك لوله ،يك فرمان را
تشکیل ميدهد که خط لولهای نامیده ميشود و پس از ، dateاجرا ميشود .حق تقدم | بیشتر از « ; » ميباشد ،همچنانکه شل سطر فرمان شما را تجزيه ميکند.
پرانتزها ميتوانند برای گروه بندی کردن فرمانها استفاده شوند :
EDT
۱۹۸۳ ۰۷:۵۱
sep ۲۸ ۲۸ ۰۸:۳۲
۰۹:۱۱:۰۹
($ )date ; who wed sep ۲۸ you
tty ۲
jpl tty ۴ $ )date ; who( | wc
sep ۸۹
۳
۱۴
خروجیهای dateو ، whoدر يك مسیل منفردی به هم ملحق ميشوند که ميتواند يك لوله را به پائین ارسال کند.
$
جريان يافتن دادهها درون يك لوله ميتواند ضبط شود و در يك فايل (اما نه در يك لولة ديگر) با فرمان teeقرار گیرد ،فرماني که
بخشي از شل نميباشد ،اما با اين وجود ،قابل استفاده برای لولههای انجام عملیات ميباشد .يك استفاده از آن ،ذخیره کردن خروجي واسطه در يك فايل ميباشد :
)date ; who( | tee save | wc
خروجي از wc
۴ ۸۹ ۱۹۸۳
۲۸ ۰۷:۵۱
EDT
sep
۲۸ ۰۸:۳۲
sep ۸۹
۳
$ cat save wed sep ۲۸
۰۹:۱۳:۲۲
tty ۲
tty ۴ < save ۱۶
$
۳
wc
you jpl $ $
teeاز ورودی خود برای فايل يا فايلهای نامگذاری شده و نیز برای خروجي خود کپي برميدارد ،در نتیجه wcهمان دادهها را دريافت
ميکند ،گويا اينکه teeدر خط لوله نميباشد.
پايان نمای ديگر فرمان ،آمپرساند $ميباشد .اين پاياننما ،دقیقاً شبیه سمي کالن يا سطر جديد ميباشد ،به جز اينکه اين علمت به شل ميگويد که منتظر کامل شدن فرمان نباشد .اساسا ً $ ،برای اجرای يك فرمان طولني مدت « در زمینه » استفاده ميشود ،همچنانکه
محیط برنامه سازی لینوکس
64/322
شما تايپ فرمانهای محاورهای را ادامه ميدهید :
طولني مدت
فرمان
$ long – running - command - id long – running – commendپردازش $ پیامواره سريعاً ظاهر ميشود
۵۲۷۳
$
با توجه به توانايي برای گروه بندی کردن فرمانها ،استفادههای جالب ديگری از پردازشهای زمینه وجود دارد .فرمان ، 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 $
جدول : ۳.۱فراکاراکترهای شل
فايل،خروجي استاندارد را به فايل ضمیمه ميکند
> > Prog > >> Prog
فايل ،ورودی استاندارد را از فايل ميگیرد
< < Prog
خروجي استاندارد P1را به ورودی استاندارد
| P2 | P1
ورودی استاندارد تا Strبعدی روی يك خط توسط خودش :سند در اينجا ادامه مييابد.
هر رشته از صفر تا چند کاراکتر را در اسامي فايلها تطبیق ميدهد هر کاراکتر منفرد را در اسامي فايلها تطبیق ميدهد
هر کاراکتر منفرد را در اسامي فايلها تطبیق ميدهد ؛
<<str *
؟ [ ]ccc
گسترههايي شبیه 9ـ 0يا a-zمجاز هستند
پايان نمای فرمان 2P :؛ 1P ، 1Pرا انجام دهد و سپس 2Pرا.
;
محیط برنامه سازی لینوکس
67/322
شبیه ; ميباشد ،اما تا اتمام 2Pمنتظر نميماند.
$
دستورات را در ...؛ اجرا مي کند خروجي را جايگزين ' '...ميکند
' '. . .
دستورات را در ...اجرا ميکند ،در يك زير شل
()...
دستورات را در ...اجرا ميکند ،در شل جاری (به ندرت استفاده مي شود)
{}...
$0 …$4توسط آرگومانها برای فايل شل جايگزين ميشود
.etc $2 , $1
مقدار متغیر شل var
$ var
مقدار var؛ از بي نظمي اجتناب ميکند ،زماني که به متن
{$}var
محلق ميشود ؛ همچنین به جدول ۵.۳مراجعه کنید.
\ Cکاراکتر Cرا به صورت حرفي ميگیرد \ ،سطر جديد ،حذف ميشود
. . .را به صورت حرفي پس از '. . . ' ، $و \ تفسیر شده ،ميگیرد،
\
« ». . .
اگر #کلمه را آغاز کند ،مابقي سطر يك توضیح ميباشد (در هفتمین
#
ويرايش وجود ندارد)
به متغیر varنسبت داده ميشود.
Var = value
; P1اجرا ميشود ،اگر موفق بود P2 ،اجرا ميشود
; P1اجرا ميشود ،اگر ناموفق بود P2 ،اجرا ميشود.
P1 $$ P2 P1 | | P2
در مثال اخیر ،چون نقل قولها ،پس از اينکه کار خود را انجام دادند حذف ميشوند ،در نتیجه echoبه صورت يك آرگومان منفرد به
نظر ميرسد که فاقد نقل قول ميباشد.
رشتههای نقل قول شده ميتوانند شامل سطرهای جديد باشند :
′ hello
$ echo > world ′ hello world $
رشتة « > » يك پیاموارة ثانويه چاپ شده توسط شل ميباشد .زماني که از شما انتظار ميرود که ورودی بیشتری را برای کامل کردن يك فرمان تايپ کنید .در اين مثال :نقل قول روی اولین سطر بايد با نقل قول ديگر متوازن شود .رشته پیاموارة ثانويه در متغیر ps2 ذخیره ميشود و ميتواند بر طبق سلیقه تغییر داده شود.
در همة اين مثالها ،نقل قول يك فرا کاراکتر ،مانع تلش شل برای تفسیر آن ميشود .فرمان
$ echo x * y
همه اسامي فايلهايي را که با xآغاز و با yپايان ميپذيرند ،پژواك ميکند .مثل همیشه ،پژواك چیزی در مورد فايلها يا فرا کاراکترهای
شل نميداند؛ تفسیر * ،اگر وجود داشته باشد ،توسل شل ذخیره ميشود.
چه اتفاقي ميافتد ،اگر هیچ فايلي با نمونه تطبیق داده نشود؟ شل به جای شکايت کردن (همچنانکه در نسخههای قبلي اين کار را انجام
محیط برنامه سازی لینوکس
68/322
داد) ،از رشته عبور ميکند ،گويا اينکه نقل قول شده است .معمول ً اين عقیده بدی است که به اين رفتار تکیه کنیم ،اما چنین رفتاری
ميتواند برای يادگیری وجود فايلهايي که يك طرح را تطبیق ميکنند ،استفاده شود :
فايلهايي وجود ندارد :پیام از lS xyzzy
وجود ميآيد
فايل ، xyzzyبا x*y *، lsتفسیر نميکند
$ ls x * y يافت نمي شود x * y $ > xyzzy
تطبیق ميشود
$ ls x *y xy zzy ′x*y′
ls
$
يافت نمي شود x * y $
يك پس کج خط در پايان يك سطر ،باعث ميشود که سطر ادامه يابد؛ و اين يك روش برای نشان دادن يك سطر بسیار طولني در شل ميباشد.
\ $ echo abc \ > def > ghi abcdefghi $
توجه داشته باشید که سطر جديد حذف ميشود ،زماني که قبل از پس کج خط ميآيد ،اما زماني که به صورت نقل قول ظاهر ميشود، باقي ميماند.
فرا کاراکتر #تقريبا به صورت جهاني برای توضیحات شل استفاده ميشود؛ اگر يك کلمه شل با #آغاز شود ،ما بقي سطر ناديده گرفته ميشود :
$ echo hello # there hello $ echo hello # there hello # there $ #بخشي از هفتمین ويرايش اصلي نبود ،اما عمیق ًا پذيرفته شده است و ما از آن در مابقي کتاب استفاده خواهیم کرد. تمرين ۳.۲خروجي تهیه شده توسط
* $ ls .را شرح دهید.
يك انحراف بر روی پژواك
اگر چه صراحتاً مورد پيگیری واقع نميشود ،اما يك سطرج ديد نهايي ،توسط پژواك تهیه ميشود .يك طرح محسوس و شايد تمیزتر برای پژواك ،پرينت کردن فقط چیزی است که درخواست ميشود .چنین چیزی ،انتشار پیاموارهها را از شل آسان ميسازد :
pure - echo Enter $يك فرمان :
محیط برنامه سازی لینوکس
69/322
سطر جديد پسین وجود ندارد
: $يك فرمان Enter
اما عیب آن ،اين است که عموميترين مورد ـ تهیه يك سطر جديد ـ پیش فرض نميباشد و نیاز به تايپ بیشتر دارد :
! $ pure – echo ′Hello >′ ! Hello $ چون يك فرمان بايد با پیش فرض عموميترين عملکرد استفاده شده خود را اجرا کند ،پژواك واقعي ،به طور خودکار ضمیمة سطر جديد نهايي ميشود.
اما اگر مطلوب نباشد چه پیش ميآيد؟ هفتمین ويرايش پژواك دارای يك اختیار منفرد – n ،و برای حذف آخرين سطر جديد ميباشد
:
: $ Enterيك فرمان
:يك فرمان echo - n Enter
ـ
$
پیامواره بر روی همان سطر – $ echo خاص ميباشد n- ،فقط
$ :ميباشد که توسط يك سطر جديد دنبال ميشود n-تنها مورد دشوار ،پژواك $ echo - n′ - n >′ -n $ اين حالت بدترکیب است اما کار ميکند و به هر حال اين يك موقعیت نادر است .يك روش متفاوت ،ارائه شده در سیستم ، Vبرای پژواك در خصوص تفسیر Cميباشد ـ شبیه توالیهای پس کج خط ،مانند \ bبرای پسبرد و ( \ cکه حقیقتا در زبان cنميباشد) برای حذف آخرين سطر جديد :
نسخه سیستم V
: \ C′يك فرمان
′ Enter
$ echo : $يك فرمان Enter
اگر چه اين مکانیسم از بي نظمي درخصوص پژواك يك علمت منها اجتناب ميکند ،اما دارای مشکلت ديگر ميباشد .پژواك اغلب به عنوان يك راهنمای تشخیص استفاده ميشود و پس کجخطها توسط تعداد زيادی از برنامههايي تفسیر ميشوند که پژواك آنقدر به بررسي آنها ميپردازد که به بينظمي اضافه ميکند.
با اين حال ،هر دو طرح پژواك دارای نکات خوب و بد ميباشند .ما ازهفتمین نسخه ويرايش ( )-nاستفاده ميکنیم ،بنابراين اگر پژواك
محلي شما از يك قرارداد متفاوت اطاعت کند ،يك جفت از برنامههای ما نیاز به تجديد نظر جزئي دارند.
پرسش ديگر در خصوص اين نظريه اين است که پژواك چه بايد انجام دهد اگر هیچ آرگوماني ارائه نشود ـ بويژه آيا بايد يك نسخه
خالي را پرينت کند و يا اينکه اصل چیزی پرينت نکند؟ همه پیاده سازيهای رايج پژواك را که ما ميشناسیم ،يك سطر خالي پرينت
ميکنند ،اما نسخههای قبلي چنین کاری را انجام نميدادند و زماني مباحثات زيادی درخصوص اين موضوع وجود داشت .داگ مکلروی ،احساسات واقعي عرفاني را در بحث و بررسي خود درخصوص موضوع ارائه داد :
محیط برنامه سازی لینوکس
70/322
يونيكس و پژواك يونیکس در سرزمین نیوجرسي ساکن بود ،يك خدمتکار زيبايي که دانشمندان از جاهای دور برای تعريف و تمجید از او مسافرت
ميکردند .همه مبهوت از عفت و پاکدامني او ،در صدد ازدواج با او بودند ،يکي به خاطر زيبايي دخترانة او ،ديگری برای فرهنگ آراسته
او ،اما فردی به خاطر زرنگي او درا جرای دقیق وظايفي که به ندرت انجام ميشد ،حتي در سرزمینهای ثروتمندتر .بنابراين قلب پر احساس و خوش برخوردی يونیکس بود که همه خواستگاران غیرقابل تحمل خود را ميپذيرفت .به زودی بسیاری از فرزندان بزرگ
شدند و موفق شدند در تمام زمین پخش شدند.
طبیعت لبخند زد و مشتاق تر از ساير مخلوقات به يونیکس جواب داد .مخلوقات متواضعتر که اندکي از رفتارهای آراستهتر ميدانستند،
از پژواك او خوشحال ميشدند ،بنابراين آنقدر واضح و روشن بود که آنها معتقدند که او ميتواند از همان سنگها و چوبهايي پاسخ
بشنود که فريادهای آنها را در میان صحرا خراب و مخدوش ميکردند .و يونیکس مطیع ،مجبور به اجرای پژواکهای کامل از هر چیزی بود که از او درخواست ميشد.
زماني که يك عاشق بي صبر از يونیکس درخواست ميکرد «چیزی را پژواك نکن» يونیکس از روی محبت دهانش را باز میکرد، چیزی را پژواك نميکرد و دوباره دهانش را ميبست .جوانان به او ميگفتند؛ منظور شما چیست که دهانت را اينگونه باز ميکني؟ از
اين به بعد ،هرگز دهانت را باز نکن زماني که نميخواهي چیزی را پژواك کني! و يونیکس اطاعت کرد.
يك جوان حساس خواهش کرد؛ اما من يك عملکرد کامل ميخواهم ،حتي وقتي که شما چیزی را پژواك نميکني و پژواکهای کامل
نميتوانند از يك دهان بسته خارج شوند .يونیکس نميخواست حتي يك نفر را ناراحت کند و پذيرفت که چیزهای متفاوتي را برای جوان بي صبر و جوان حساس بیان کند .او جوان حساس را با « »\ nفرا ميخواند.
زماني که او« » \nرا بیان ميکرد ،او حقیقتا ً چیزی نميگفت بنابراين بايد دهانش را دوبار باز ميکرد يك بار برای گفتن« »\ nو بار
ديگر برای گفتن هیچ چیزی ،و بنابراين او جوان حساس را راضي نکرد و جوان حساس بلفاصله گفت ،صداهای \nيك پژواك کامل برای من هستند اما بار دوم آن را خراب ميکند .من از تو ميخواهم که يکي از آنها را انتخاب کني ،بنابراين يونیکس که نميتوانست با
ايجاد دردسر و مزاحمت زندگي کند ،موافقت کرد که برخي از پژواکها را از بین ببرد و آن را « » \ cبنامد .اکنون جوان حساس ميتوانست با درخواست« » \cو « » \nبا هم ،يك پژواك کامل از چیزی داشته باشد .اما آنها میگويند که او به خاطر تعداد زياد
نمادگذاریها فوت کرد ،قبل از اينکه او حتي يکي از آنها را بشنود.
ل بسنجید. تمرين .۳.۳پیشبیني کنید که کدام يك از فرمانهای grepزير انجام خواهند شد ،سپس درك خود را عم ً
grep grep grep grep grep
\$ \\ $ \\\$ ′\$′ ′\′$′
grep grep grep grep grep
فايلي که حاوی اين فرمانها باشد ،يك مورد آزمون خوبي ميباشد ،اگر شما بخواهید امتحان کنید.
\\ \\ \\ '' \'' $ ''' ' $ '' '' $
تمرينـ . ۳.۴شما چگونه به grepميگويید که به جستجوی يك طرحي بپردازد که باـ « ــ » aآغاز ميشود؟ چرانقل قول کردن
محیط برنامه سازی لینوکس
71/322
آرگومان کمك نميکند؟ نکته :در مورد انتخاب Cـ تحقیق کنید.
تمرين ۳-۵توجه کنید به
آيا اين فرمان همه اسامي را در همة جهتها تهیه ميکند؟ اسامي بر طبق چه نظمي آشکار ميشوند؟
*$ echo */
تمرين ( ۳-۶پرسش راهکار) .شما چگونه يك /را در يك اسم فايل قرار ميدهید (يعني ،يك /که قطعات مسیر را جدا نميکند)؟ تمرين ۳-۷با فرمان و با فرمان
$ cat xy / y $ cat x >> x
چه اتفاقي رخ ميدهد؟
قبل از اينکه به بررسي آنها بپردازيد فکر کنید.
تمرين ۳-۸اگر شما فرمان
* $ rm
را تايپ کنید ،چرا rmنميتواند به شما اخطار دهدکه شما در حال حذف همه فايلهای خود هستید؟ ۳.۳ايجاد فرمانهای جديد
اکنون وقت آن رسیده است که به سراغ چیزی برويم که در فصل اول قول داديم ـ چگونه فرمانهای جديد را خارج از فرمانهای قبلي ايجاد کنیم.
با توجه به يك توالي از فرمانهايي که بیشتر از چندين بار تکرار ميشوند ،بهتر است که اين توالي را در يك فرمان جديد با نام خودش
قرار دهیم ،در نتیجه شما ميتوانید از آن به عنوان يك فرمان منظم استفاده کنید .برای روشن شدن اين موضوع ،فرض کنید که قصد
شمارش کاربرها را غالب ًا با خط لولهای
داريد که در فصل اول ذکر شد و شما ميخواهید يك برنامه جديد nuرا برای انجام آن بوجودآوريد.
who | wc - 1
$
اولین مرحله ايجاد يك فايل معمولي است که شامل ' ' who | wc – 1ميباشد شما ميتوانید از يك ويراستار مطلوب استفاده کنید و
يا ميتوانید از قوه خلقیت استفاده کنید :
′ who | wc – 1 ′ > nu
(بدون نقل قولها ،چه چیزی در nuظاهر ميشود؟)
echo
$
همانگونه که در فصل اول بیان کرديم ،شل يك برنامه شبیه يك ويراستار يا whoو يا wcميباشد؛ و نام آن shاست .و چون يك
برنامه است ،شما ميتوانید آن را اجرا کنید و به ورودی آن مجددا ً جهت دهید .بنابراين شل را با ورودی منتج ازفايل nuآن به جای
پايانه ،اجرا کنید:
tty tty tty
2 you 4 you 5 you
$ who 07:51 28 sep 10:02 28 sep 09:38 28 sep
محیط برنامه سازی لینوکس
72/322
you
sep
4 tty
خروجي شبیه همان چیزی خواهد بود که در هنگام تايپ who | wc -1در پايانه ميباشد.
10:17 28 $ cat na Who : wc -1 $ sh>nu 4 $
دوباره همانند ساير ـ برنامهها ،شل ورودی خود را از يك فايل ميگیرد ،اگر فايلي به عنوان يك آرگومان نامگذاری شود ؛ شما
ميتوانستید برای رسیدن به همان نتیجه بنويسید
اما تايپ کردن « » shدر هر مورد ،درد سر و زحمت ميباشد:
چون طولنيتر است و تمايزی را بین برنامه های نوشته شده در
$ sh nu say ،cو برنامههای نوشته شده از طريق اتصال برنامهها با شل ،
بوجود ميآورد .بنابراين ،اگر يك فايل اجراپذير باشد و اگر شامل متن باشد ،در نتیجه شل ،آن را به عنوان يك فايل از فرمانهای شل
تصور ميکند .چنین فايلي ،فايل شل نامیده ميشود.
همه کاری که شما بايد انجام دهید ،اجرا پذيرکردن nuميباشد و در ابتدا:
$ chomd + x nu
و پس از آن شما ميتوانید آن را با ،$ nuراه اندازی کنید.
از اکنون کاربرهای nuفقط با اجرا کردن آن نميتوانند بگويند که شما آن را به اين روش آسان پیاده کنید.
روشي که شل حقیقتاً nuرا اجرا ميکند ،ايجاد يك فرآيند جديد شکل دقیق ًا به گونهای که شما $ sh nuرا تايپ کردهايد ميباشد.
اين شل مولود ،زير شل نامیده ميشود ـ يك فرآيند شلي که توسط شل جاری شما راهاندازی ميشود ، Shnu .همانندـ sh<nu نميباشد ،چون ورودی استاندارد آن ،هنوز متصل به پايانه ميباشد.
همانگونه که هست nu ،فقط زماني که کار ميکند که در فهرست جاری شما باشد ( البته مشروط بر اينکه فهرست جاری در مسیر شما باشد ،که از حال به بعد ما اينگونه تصور ميکنیم) .برای ايجاد nuبه عنوان بخشي از مجموعه عملکردهای خود،بدون توجه به اينکه
شما در کدام فهرست قرارداريد ،به فهرست binاختصاصي خود وارد شويد و / usr/you/binرا به مسیر جستجوی خود اضافه کنید:
$ mkdir bin
pwd $ usr/yo u / بسازيد اگر قبل اين کار را انجام ندادهايد binيك
echo $ PATH $ asr/you/bin:/bin:/usr/bin /: mv nu bin $ nuحقیقتاً از فهرست جاری ميآيد اما توسط شل يافت ميشود
مسیر را برای اطمینان کنترل کنید
بايد اينگونه باشد
را نصب کنید nu $ ls nu يافت نميشود $ nu
4 $
البته ،مسير PATKشما بايد به طور صحيح با برش عرضي profileشما متناسب باشد،
محیط برنامه سازی لینوکس
73/322
بنابراين شما نبايد هرزماني كه به سيستم وارد ميشويد ،آن را ريست سازي كنيد.
فرمانهاي ساده ديگري وجود دارند كه شما ميتوانيد به اين روش براي مناسب كردن محيط خود بر طبق سليقه خود بوجود آوريد .برخي از فرمانهايي كه به نظر ما مناسب ميباشند ،شامل موارد زير هستند:
Cs0كه توالي صحيح كاراكترهاي مرموز را براي پاك كردن نمايشگر روي پايانه شما پژواك مي كند ( ۲۴سطر جديد يك اجراي كلي مطلوب ميباشد)؛ ، What 0كه whoو ps - aرا براي بيان اينكه چه كسي به سيستم وارد ميشود و چه كاري انجام ميدهد اجرا ميكند؛ Where 0كه شناسايي اسم سيستم يونيكسي را كه شما از آن استفاده ميكنيد پرينت ميكند -اين فرمان قابل استفاده ميباشد اگر شما به طور منظم از آن استفاده كنيد( . تنظيم ps1نيز به همين منظور ميباشد).
تمرينت . ۳.۹بهت تفرمان / bin,/usr/binمراجعه تكنيد تبراي تاينكه تببينيد تچندت تفرمان تحقيقتًا فايلهاي شل ميباشند .آيا ميتوانيد اين كار را با يك فرمان انجام دهيد؟ نكته :فايل (.)1
حدسيات بر اساس طول فايل چقدر صحيح ميباشند؟ . ۳.۴پارامترها و آرگومانهاي فرمان
اگر چه nuهمانگونه كه هست ،مناسب ميباشد ،اما اكثر برنامههاي شل ،آرگومونها را تفسير ميكنند ،در نتيجه براي مثال ،اسامي فايلها و انتخابها ميتوانند خاص باشند زماني كه برنامه اجرا ميشود.
فرض كنيد ما ميخواهيم برنامهايرا بسازيم كه cxناميده ميشود براي اينكه حالت يك فايل را براي قابل اجرا شدن تغيير دهيم ،بنابراين nu $
cx
يك صورت مختصر براي chomd+xnu $
ميباشد ،ما به ميزان كافي براي انجام چنين چيزي اطلعات داريم .ما به يك فايل با نام cxنياز داريم كه محتواي آن Chomd + x filename
محیط برنامه سازی لینوکس
74/322
ميباشد .تنها مورد جديدي كه ما بايد بدانيم اين است كه چگونه بهت cxبگوييم كه نام فايل چيست ،چون در هر زماني كه cxاجرا ميشود ،نام فايل متفاوت است.
زماني كه شل ،يك فايل از فرمانها را اجرا ميكند ،هر رخداد از ،1$توسط اولين آرگومان جايگزين ميشود ،هر $2توسط دومين آرگومان جايگزين ميشود و به همين ترتيب تا $9
ادامه مييابد .بنابراين اگر فايل cxشامل Chomd+x $1
باشد ،زماني كه فرمان ت $ cx nuاجرا ميشود ،زير شل،ت " " 1$را با اولين آرگومان خود يعني « » nuجايگزين ميكند. اكنون ميخواهيم به توالي كل عملكردها نگاهي بيندازيم:
Cxرا به شكل اوليه ايجاد كنيد
>cx
Cxرا قابل اجرا كنيد يك برنامه آزمايشي ايجاد كنيد
'$ echo chomd + x $1
cx
$ sh cx
$ echo echo Hi, there !>hello
آن را بررسي كنيد
hello
$
نميتواند اجرا شود
hello :
آن را قابل اجرا كنيد
$ cx hello
دوباره بررسي كنيد
$ hello
Hi, there! Cxرا نصب كنيد
كار ميكند $ mv CX/urr/you/bin
پاكسازي كنيد
$ rm hello $
توجه داشته باشيد
كه ما گفتيم $ 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
c:
$ cd/usr/you/bin $ cat 1c تعداد سطرها را در فايلها بشماريد
1 #
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نامگذاری شده باشد و شامل سطرهايي مانند زير باشد 3838ت 976ت 2
dial – a – joke
4200ت 246ت ial – a – prayer 212 3636ت 976ت ial santa 212 dow Jones report 4141ت 976ت 212
محیط برنامه سازی لینوکس
76/322
در نتیجه فرمان 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 dial - a – prayer dial santa در اينجا چیزی اشتباه است
ـ 246ـ 4200 212 ـ 976ـ 3636 212
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عبور خواهد کرد ،حتي اگر دارای فاصلههای خالي باشد.
212-976-4141 به راستي ،شما مي توانید ( grepوبنابراين ) ۴۱۱را مستقل از مورد و با انتخاب y-بسازيد:
dow jones 411 $ dow jones report
…$ grep - y pattern با ، -yحروف موردی پايین در طرح نیز با حروف موردی باليي در ورودی ،متناسب خواهند بود( .اين انتخاب در هفتمین ويرايش grepوجود دارد ،اما در سايرسیستمها وجود ندارد).
محیط برنامه سازی لینوکس
77/322
چهار نکته در مورد آرگومانهای فرمان وجود دارند که ما تا فصل ۵آنها را ناديده ميگیريم ،اما يکي از آنها ،چیز با ارزشي در اينجا ميباشد .آرگومان ،$ 0نام برنامهای است که اجرا ميشود ـ در cx ،$0به صورت« » cxميباشد .يك استفاده جديد از $0در پیاده
سازی برنامههای ۲و ۳و ۴و … ميباشد که ورودی خود را در ستونهای زيادی پرينت ميکنندwho | 2 $ :
28 21:09 28 22:11 28 19:58
tty 5 tty 7 b tty
cvw scj J1b
21:23 22:10 23:00
sep sep sep
28 28 28
ttyo 4Tty ttyg
drh dmr You
$ پیاده سازيهای 2و 3و … مشابهه هستند؛ و در حقیقت آنها مرتبط به همان فايل هستند:
1n 26؛ 1n 25؛ 1n 24؛ 1n $ 3 2 ] -1i - $ 1s [9-1 16722 16722 16722 16722 16722
28 23:21 2 28 23:21 3 28 23:21 4 28 23:21 5 28 23:21 6 1s/usr/you/bin $ | 5 4 411 5 6 m nu where what cat 5 $ 3 … :و 2و# در nستون پرينت کنید *$
5 5 5 5 5
-rwxrwxrwx -rwxrwxrwx -rwxrwxrwx -rwxrwxrwx -rwxrwxrwx
you you you you you
3 cx
51 51 51 51 51
sep sep sep sep sep
2 1c
-Pr-$o-t 11
$
انتخاب ،-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بخشي از
هفتمین ويرايش نميباشد ،اما آنقدر آسان و مفید است که ما نسخههای مربوط به آن را در فصل ۵و ۶گنجاندهايم.
فرض کنید شما دومین نسخه از فهرست نامهرساني را داريد .سپس
$ mail 'pick\ 'mailing list\ "<letter don?y ?whr ?ejs mb?y $ نامه را به donو mbميفرستد .توجه داشته باشید که نقل قولهای گذشته تو در تو وجود دارند؛ پس کج خطها از تفسیر داخل « … »
محیط برنامه سازی لینوکس
79/322
در طول تجزيه مورد بیروني ،جلوگیری ميکنند.
تمرين . ۳.۱۰اگر پس کج خطها درفرمان $
..\ echo 1 'echo\'date
تمرين 'date' $ . ۳.۱۱را بررسي کنید و نتیجه را شرح دهید.
تمرين ۳.۱۲
$ grep -1 pattern filenames اسامي فايلهايي را لیست ميکند که در آنها يك تطبیق از طرح وجود دارد ،اما خروجي ديگری را تولید نميکند .برخي از تغییرات را بر
روی
$ 'command 'grep -1 pattern filenames
بررسي کنید.
۳.۶متغيرهاي شل شل ،همانند اکثر زبانهای برنامهنويسي دارای متغیرهايي ميباشد که در زبان حرفهای شل ،گاهي اوقات پارامتر نامیده ميشوند.
رشتههايي مانند ،$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
به جايي ديگر برويد
$
از متغير در يك اسم فايل استفاده كنيد
cd/usr/mary/bin $
1n $dir/cx …$
براي مدتي كار كنيد برگرديد
cd $dir $ pwd $ usr/you/bin/ $
مجموعه فرمان توکار شل ،ارزشهای همه متغیرهای تعريف شده شما را نشان ميدهد .برای ديدن فقط يك يا دو متغیر ،پژواك مناسبتر
است.
$ set Home=/usr/you =IFS PATH=:/usr/you/bin:/bin:/usr/bin PS1=$ >=PS2 Dir=/usr/uou/bin $ echo $dir /usr/you/bin $ ارزش يك متغیر ،وابسته به شلي ميباشد که آن را بوجود ميآورد و به طور خودکار از اولد شل عبور نميکند .
xرا بوجود آوريد
x = Hello $
مثل جديد
sh $
$ echo $ x
فقط سطر جديد X :بدون تعريف در زير شل
اين شل را ترك کنید
ctl-d $
به شل اولیه برگرديد
$
echo $ x
xتعريف ميشود
Hello
$
اين فرمان به اين معناست که فايل شل نميتواند ارزش يك متغیر را تغییر دهد ،چون فايل شل توسط يك زير شل اجرا ميشود:
يك فايل دوسطری ايجاد کنید…
......برای تعیین و پرينت X cat setX $ "X="GoodBye Echo $X echo $ X $
$
"X="GoodBye $ > echo $ X" > set X
"echo
محیط برنامه سازی لینوکس
81/322
xهر شل اوليه ،سلم ميباشد
Hello sh setx $
xدر زير شل خداحافظ ميباشد…
Good Bye echo $ X $
اما هنوز سلم در اين شل ميباشدHello … $ اما زمانهايي وجود دارند که استفاده از يك فايل شل برای تغییر متغیرهای شل مفید ميباشد .يك مثال بديهي اين است که يك فايل، يك فهرست جديد به ـ PATHشما اضافه ميکند .بنابراين شکل يکفرمان « ( » .نقطه) مي سازد که فرمانها را دريك فايل در شل
جاری اجرا مي کند ،به جای اينکه در زير شل اجرا کند .چنین چیزی در ابتدا اختراع شد ،در نتیجه افراد ميتوانستند به طور مناسب
فايلهای prfileخود را بدون ورود مجدد به سیستم ،مجدد ًا اجرا کنند ،اما اين اختراع استفادههای ديگری نیز دارد:
$ cat / usr / you / bin / games PATH= $ PATH : /usr/ games $ echo $ PATH :/ usr / you / bin : / bin : / usr / bin $ . games $ echo $ PATH :/ usr / you / bin : / bin : / usr / bin : / usr / games
فايل برای فرمان « » .با مکانیسم PATHجستجو ميشود ،در نتیجه مي تواند در فهرست binشما جايگزين شود.
زماني که يك فايل با « » .اجرا ميشود ،فقط به صورت ظاهری شبیه اجرای يك فايل شل مي باشد .فايل در مفهوم معمول کلمه اجرا
نمي شود .در عوض ،فرمانهای موجود در آن ،دقیقاًـ تفسیر ميشوند ،گويا اينکه شما آنها را به صورت محاورهای تايپ کردهايدـ -
ورودی استاندارد شل موقتاً برای خارج شدن از فايل تغییر مسیر ميدهد .چون فايل خوانده مي شود اما اجرا نميشود ،نبايد مجوزهای
اجرا داشته باشد .تفاوت ديگر اين است که فايل آرگومانهای سطر فرمان را دريافت نمي کند؛ در عوض $1 ،و $2و مابقي ،خالي هستند .اگر آرگومانها عبور ميکردند خوب بود ،اما آنها عبور نميکنند.
روش ديگر برای تعیین ارزش يك متغیر در يك زير شل ،نسبت دادن آن به طور آشکارا به سطر فرمان ،قبل از خود فرمان مي باشد: echo echo $ x’ > echo x $ CX echo x $
همانند قبل
echox $
ارزش xاز زير شل عبور کرد
echo $ x $ در زير شل تعیین نميشود x
Hello
x = Hi echo 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 .شمع را خاموش کنید ؛ کتاب را ببنديد ؛ زنگ را به صدا درآوريد $ echo $ PATH : / usr / you / bin: / bin: / usr / bin $ cat / usr / you / bin / games PATH = $ PATH :/ usr / games $ . games $ fortune
- Khuthبهینه سازی پیش از موقع ،ريشة همه مضرات است PATH
$ echo $ PATH در اين زمان تغییر ميکند : / usr / you / bin: / bin: / usr / bin: / usr / games
$ استفاده کردن از هر دو مکانیسم دريك فايل شل مفرد ،امکان پذير است .يك فرمان gamesاندکي متفاوت مي تواند برای اجرای يك gameتنها بدون تغییر PATHاستفاده شود و يا ميتواند PATHرابه طور دائم برای قرار دادن usr/games/تعیین کند:
* $ PATH = $ PATH : / usr / games /usr/gamesندارد
هنوز وجود ندارد اکنون وجود دارد
توجه كنيد *$به
$ cat / usr / you / bin / games
$ CX / usr / you / bin / games $ echo $ PATH :/ usr / you / bin:/ bin: / usr / bin
$ games fortane I'd give my right arm to be ambidextrous. $ echo $ PATH :/ usr / you / bin:/ bin:/ usr / bin $ . games $ echo $ PATH :/ usr / you / bin:/ bin:/ usr / bin:/ usr / games $ for tune فردی که ترديد داشت ،گاهي اوقات ذخیره ميشود
$ اولین فراخواني برای ،gamesفايل شل را در يك زير شل اجرا کرد ،جايي که PATHبه طور موقتي برای ايجاد usr/games/تغییر کرد .در عوض دومین مثال ،فايل را در شل جاری با * $رشتة خالي تغییر کرد ،بنابراين فرماني بر روی سطر وجود نداشت و PATH
محیط برنامه سازی لینوکس
83/322
تغییر کرد .استفاده از gamesبه اين دو روش دشوار است ،اما منجر به يك مسیر ساده ميشود که برای استفاده ،مناسب و طبیعي است.
زماني که شما مي خواهید ارزش يك متغیر را در زير شلها ،قابل دستیابي کنید ،از فرمان exportشل بايد استفاده شود( .شما ممکن است فکر کنید که چرا راهي برای صدور ارزش يك متغیر ازيك زيرشل به سقف آن وجود ندارد). در اينجا يکي از مثالهای قبلي ما وجود دارد ،اکنون با متغیر صادر شده:
$ x = Hello $ export x $ sh
شل جديد
xمعروف در زير شل ارزش آن تغییر دهید
$x
$ echo
Hello ' $ x = 'Good Bye
از شل خارج شويد
به شل اولیه برگرديد x still Hello
$ echo $ x GoodBye $ ctl – d $ $ echo $ x Hello $
expor tدارای معنای دقیقي ميباشد ،اماحداقل برای اهداف روزمره ،يك دستور ورق زدن ،کافي ميباشد ؛ مجموعه متغیرهای موقت را برای راحتي کوتاه مدت صادر نکنید ،اما همیشه متغیرهايي را صادر کنید که ميخواهید در تمام شلها و زير شلهای خود ست کنید( .برای مثال شامل شلهايي که با فرمان ! S’ edآغاز ميشوند).
بنابراين ،متغیرهايي که برای شل ،خاص ميباشند ،مانند PATHو ،HOMEبايد صادر شوند.
تمرين ۳.۱۳چرا ما همیشه فهرست جاری را در PATHقرارميدهیم؟ اين فهرست در چه جايي بايد قرار گیرد؟ ۳.۷مطالبي بیشتر در خصوص جهت دهي مجدد 1/0
خطای استاندارد اختراع شد ،در نتیجه پیغامهای خطا همیشه بر روی رايانه ظاهر ميشوند:
diff file 1 file 2 > diff. Out $ چنین فايل يا فهرستي وجود ندارد : diff : file 2 $
مطمئنا ً مطلوب است که پیغامهای خطا به اين روش کارکنند ـ بسیار ناخوشايند ميباشد اگر آنها در diff . outناپديد شوند و شما با
اين تصور باشید که فرمان نادرست diffبه درستي کار کرده است.
هر برنامه دارای سه فايل پیش فرض ميباشد که زماني برقرار ميشوند که برنامه آغاز ميشود ،اين سه فايل پیش فرض با اعداد صحیح
کوچك شماره ميگیرند و توصیف گران ميشود ،اين سه فايل پیش فرض با اعداد صحیح کوچك شماره ميگیرند و توصیف گران
فايل نامیده ميشوند (ما در فصل ۷به آنها مراجعه خواهیم کرد) .ورودی استاندارد« » 0و خروجي استاندارد « » 1که ماقبل ً با آنها
محیط برنامه سازی لینوکس
84/322
آشنا شديم ،اغلب از فايلها و لولهها و يا به طرف فايلها و لولهها تغییر جهت ميدهند .خروجي با شمارة ، ۲يك خروجي خطای
استاندارد ميباشد و در حالت عادی راه خود را به سمت پايانة شما پیدا ميکند.
گاهي اوقات ،برنامهها ،خروجي را بر روی خطای استاندارد تولید ميکنند حتي زماني که آنها به درستي کار ميکنند .يك مثال عمومي،
زمان برنامه ميباشد که يك فرمان را اجرا ميکند و سپس به خطای استاندارد گزارش ميدهد که چقدر زمان ميگیرد.
ch 1 . 3
2 > time . out
$ time wc ch 1 . 3 22691 4288 931 real 0/1 rse 4/0 sys 4/0
$ thime wc ch 1 . 3 >wc .out real 2/0 user 0/4 Sys 0/3 $ time wc ch 3.1 > wc . out $ cat time – out 1/0 4/0 0/3
real user sys $
ساخت ( filename >2هیچ فاصلهای بین 2و > نبايد باشد) خروجي خطای استاندارد را به درون فايل هدايت ميکند ؛ اين ساختار از
نظر نحوی نامناسب است اما کارش را انجام ميدهد( .زمانهای ايجادشده توسط timeبرای آزمايش کوچکي مانند اين نمونه صحیح
نمي باشند .اما يك توالي از آزمايشات بلندتر ،اعداد مفید و به طور معقول قابل اعتماد هستند و شما ممکن است به خوبي بتوانید آنها را برای تحلیل بیشتر ذخیره کنید؛ برای مثال به جدل ۸.۱مراجعه کنید).
همچنین اين امکان وجود دارد که دو مسیل خروجي را در هم ادغام کنیم:
$ time wc ch 1 . 3 >wc .out 2 >$ 1 $ cat wc out 22691 4288 931 ch 1 . 3 real 1/0 user 0/4 sys 0/3 $ نمادگذاری 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 دريك سند در اينجا ،جايگزين ميکند ،مگر اينکه بخشي از کلمه با نقل قولها يا يك پس کج خط ،نقل قول شود؛ در اين مورد ،کل
سند ،به صورت حرفي ميشود.
ما به موضوع اسناد در اينجا ،در پايان فصل ،با يك مثال جالب تر مراجعه ميکنیم.
جدول . ۳.۲جهت دهي های مجدد و متعدد ورودی ـ خروجي را که شل آنها را درك ميکند ،لیست ميکند.
تمرين . ۳.۱۴نسخة سند در اينجای ۴۱۱را با نسخة اصلي مقايسه کنید .کدام يك راحتتر قابل نگهداری است؟ کدام يك مبنای بهتری برای يك سرويس کلي ميباشد؟
جدول :۳.۲جهت دهي های مجدد I/Oدر شل
خروجي استاندارد رابه سمت فايل هدايت ميکند خروجي استاندارد رابه فايل پیوست ميکند >file
<file
<< fileورودی استاندارد را از فايل ميگیرد
خروجي استاندارد برنامة 1Pرا به ورودي 2Pمتصل ميكند مترادف را براي | خارج ميكند خروجي را از توصیفگر فايل nبه فايل هدايت ميکند
خروجي را از توصیفگر فايل nبه فايل پیوست مي کند
خروجي توصیفگر فايل nرا در توصیفگر فايل mادغام ميکند
n>file n>>file n>$ m
P. | P ∧
2
محیط برنامه سازی لینوکس
86/322
ورودی توصیفگر فايل nرا در توصیفگر فايل mادغام ميکند
سند در اينجا :ورودی استاندارد را ميگیرد ،تا زمان Sبعدی
n<$m >>S
در آغاز يك سطر ؛ آن را جايگزين '…' ، $و 1ميکند
سند در اينجا بدون جايگزيني
>> S1
سند در اينجا بدون جايگزيني
'>> 'S
۳.۸حلقه سازي در برنامههاي شل شل ،حقیقتا ً يك زبان برنامه نويسي ميباشد :شل دارای متغیرها ،حلقهها ،تصمیمگیری و مواردی از اين قبیل ميباشد .ما در اينجا به بحث و بررسي درخصوص حلقه سازی اساسي ميپردازيم و درخصوص روند کنترل در فصل ۵صحبت ميکنیم.
حلقهای کردن يك مجموعه از اسامي فايلها ،بسیار عمومي است و بیان 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
> don | pr - h "diff 'pwd' / old 'pwd' " | lpr $ 3712 process -id $ ما خروجي را به prو lprاز طريق لوله متصل کرديم برای اينکه شرح دهیم اين امکان وجود دارد که :خروجي استاندارد برنامهها در
يك ، forوارد خروجي استاندارد خود forشود .ما يك عنوان خیالي را با انتخاب - hاز ،prبر روی خروجي قرار ميدهیم و از دو
فراخواني توکار pwdاستفاده ميکنیم .و ما کل توالي را طوری ست ميکنیم که به طور ناهمگام ( )$اجرا شود ،در نتیجه ما نبايد برای
اجرای آن صبر کنیم ؛ $برای تمام حلقه و خط لولهای بکار ميرود.
ما ترجیح ميدهیم که يك بیان forرافرمت کنیم ،همانگونه که نشان داده ميشود ،اما شما ميتوانید از اندازهای آن را متراکم کنید .
محدوديتهای مهم do ،و doneميباشند که فقط به عنوان لغات کلیدی شناخته ميشوند ،زماني که دقیقاً پس از يك سطر جديد يا سمي
کالن ظاهر ميشوند .براساس اندازة forگاهي اوقات بهتر است که آن را تمام ًا روی يك سطر بنويسیم:
for i in list ; do commands ; done شما بايد از حلقة forبرای فرمانهای متعدد و يا در جايي استفاده کنید که پردازش آرگومان توکار در فرمانهای منفرد ،مناسب نميباشد . اما از آن ،زماني که فرمان منفرد ،اسامي فايلها را حلقه سازی ميکند ،استفاده نکنید:
اين فرمان پائین تر از فرمان زير ميباشد:
# poor idea: * for I in $ do < homd +× $I done
* $ × + Chomd چون حلقة forيك chomdمجزارا برای هر فايل اجرا ميکند ،که در دستگاههای کامپیوتر پرهزينهتر ميباشد ( .اما اطمینان داشته
باشید که شما تفاوت بین
* for i in
را که همة اسامي فايلها را دريك فهرست جاری حلقه بندی ميکند و
* $ for i in
را که همة آرگومانها را برای فايل شل حلقهبندی ميکند ،درك ميکنید).
فهرست آرگومان برای يك ، forاغلب از طرحي ميآيد که منطبق با اسامي فايلها ميباشد اما ميتواند از هر جای ديگری نیز بیايد .اين فهرست ميتو
' $ for i in 'cat .... باشد و يا ارگومانها نمي توانند تايپ شوند .برای مثال ،قبل در اين فصل ما يك گروه از برنامه ها را برای پرينت چند ستوني ،با عناوين
۲و۳ .و از اين قبیل بوجود آورديم .اين موارد خطوط پیوند به يك فايل تنها مي باشند که مي تواند ساخته شود ،زماني که فايل ۲به اين
صورت نوشته مي شود:
for i in
Done ; $I 2 in do ; 6 5 4 3 $ $
به عنوان يك استفادة تاحدودی جالبتر از forما ميتوانیم از pickاستفاده کنیم برای اينکه انتخاب کنیم کدام فايلها را با ساير فايلهای موجود در فهرست پشتیبان مقايسه کنیم:
' *for i in 'pick ch2.
$
محیط برنامه سازی لینوکس
88/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وجود دارد که فايلها را در يك فايل شل خود توضیح بر روی خروجي استاندارد آن ،گروهبندی ميکند:
$ cat bundle # bundle : group filles into distribution package 'echo '# To unbundle , sh this file for i do "echo "echo $i 1>$2 "'echo "cat >>ii << 'End of $ i cat $i "echo "End of $i done $ نقل قول کردن « »End of $iاطمینان ميدهد که همة فراکاراکترهای شل در فايلهای ناديده گرفته ميشوند. در حالت طبیعي ،شما بايد قبل از وارد کردن آن بر روی ، somewhere 1bobآن را بررسي کنید:
$ bundle CX 1C > junk $ cat junk # To unbundle , sh this file echo CX 1>$ 2 'cat SCX <<'End of CX *chomd +× $ End of CX Echo 1C 1>$2 'Cat >1C <<'End of 1C # 1C : count numbr of lines in files * $ـ wc 1
Try it out
looks good
End of 1C $ mkdir test $ cd test $ sh .. / junk cx 1c $ 1S cx 1c
$ cat CX *chomd +× $ $ cat 1C # 1C : count number of lines infiles * $ـ wc 1 $ cd ..
محیط برنامه سازی لینوکس
90/322
clean up send the files
$ rm junk test /*; rmdir test $ pwd /usr/you/bin $ bundle 'pick * '| mail / somewhere !bob
اگر يکي از فايلهايي که شما ميفرستید برحسب اتفاق دارای يك سطر به شکل زير باشد:
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
متغیر را در منبع cقرار دهید grep from $ maIl
$
grep from $ maIl | grep – v mary
[$ grep – n variable * . ]ch عنوانهای پیام را در صندوق پستي پرينت کنید نبودند maryعنوانها از
$
$ grep – y mary $ Home/lib/phone-book who | grep mary
$
$ Is | grep – v temp
شماره تلفن مری را پیدا کنید
ببینید که آيا مری با سیستم ارتباط دارد
نميباشند tempاسامي فايلهايي که شامل
انتخاب – ، nتعداد سطرها را پرينت ميکند ،انتخاب – ، vحس امتحان را تبديل ميکند و – yحروف جعبه پائیني را در حروف
تطبیق طرح همان جعبه در فايل ميسازد (جعبه باليي نیز فقط جعبه باليي را تطبیق ميدهد).
در همه مثالهايي که تاکنون مشاهده کردهايم grep ،به دنبال رشتههای معمولي حروف و اعداد بوده است .اما grepميتواند حقیقتا ً در
جستجوی طرحهای پیچیدهتر باشد ، grep :بیانها را در يك زبان ساده برای توصیف رشتهها تفسیر ميکند.
از نظر تکنیکي ،طرحها اندکي يك شکل محدود شده از مشخص کنندههای رشته ميباشند و عبارت منظم نامیده ميشوندGrep .
همان عبارت منظم مانند edرا تفسیر ميکند؛ در حقیقت grepدر ابتدا (در يك بعدازظهر) از طريق عمل مستقیم بر روی edبوجود آمد.
عبارتهای منظم با دادن معني ويژه به کاراکترهای خاص ،مشخص ميشوند ،درست شبیه * و غیره که توسط شل استفاده ميشوند .فرا
کاراکترهای بیشتری وجود دارند و متاسفانه دارای تفاوتهايي در معاني خود ميباشند .جدول ۴.۱همه فراکاراکرهای عبارت منظم را
نشان ميدهد اما به طور خلصه در اينجا به مرور آنها ميپردازيم.
فرا کارکترهای ^ و $طرح را برای شروع (^) يا پايان ( )$سطر تثبیت ميکنند .برای مثال ، فايلهايي را که شامل Fromميباشند در صندوق پستي شما قرار ميدهد اما
grep From $ MAIL
$
$ grep ′^ From′ $ MAIL سطرهايي را پرينت ميکند که با Formآغاز ميشوند ،که به احتمال قوی سطرهايي با عنوان پیغام ميباشند .فراکاراکترهای عبارت
منظم ،با فراکاراکترهای شل همپوشاني ميکنند ،بنابراين همیشه يك عقیده خوب برای ضمیمه کردن طرحهای grepدر نقلهای منفرد وجود دارد.
،grepطبقههايي از کاراکترها را حمايت ميکند که بسیار شبیه به کارکترهای موجود در شل ميباشند ،بنابراين [ ،]a-zهر گونه حرف
در جعبه پائیني را تطبیق ميکند .اما تفاوتهايي وجود دارند :اگر يك طبقه از کاراکتر grepبا يك سیرکومفلکس ^ ،آغاز شود طرح هر
کاراکتری را تطبیق ميکند ،به جز کاراکترهايي را که در طبقه وجود دارند .
بنابراين ]9– 0 ^ [ ،هر گونه کاراکتر غیر رقمي را تطبیق ميکند .همچنین در شل يك پس کج خط از lو ــ ،در يك طبقه از کاراکتر
محافظت ميکند ،اما grepو edمستلزم اين هستند که کاراکترها درجايي آشکار شوند که معني آنها مبهم نباشد .برای مثال]-[ ]sil[ ،
[ ] ،يك کروشه مربع بسته يا باز و يا يك علمت منها را تطبیق ميکند.
يك دوره « » .معادل ؟ شل ميباشد :هر گونه کاراکتری را تطبیق ميکند( .دوره احتمال کاراکتر با متفاوتترين معني برای برنامههای
محیط برنامه سازی لینوکس
95/322
متفاوت يونیکس ميباشد) در اينجا دو مثال وجود دارد :
فهرست اسامي راهنماي فرعي
$
Is - 1 | grep ′^d′
فهرست فايلهايي كه ميتوانند خوانده و نوشته شوند $
Is - 1 | grep ′^ …… rw′
« ^ » و هفت د وره ،هر هفت کاراکتر را در آغاز سطر تطبیق ميدهند[ ،زماني که از خروجي Is-1به معنای هر رشته مجاز ،استفاده ميکنند.
عملگر ستبار * برای کاراکتر يا فراکاراکتر قبلي (شامل يك طبقه از کاراکتر) در عبارت بکار ميرود و آنها جمعاً تعداد تطبیقهای موفق کاراکتر يا فراکاراکتر را تطبیق ميکنند .برای مثال *x ،يك توالي از x’sرا تا جايي که امکان دارد تطبیق ميکند،
[ ، * ]a – ZA – Zيك رشته الفبايي را تطبیق ميکند * ،هر چیزی را تا سطر جديد تطبیق ميکند و * ، .xهر چیزی را تا زمان داشتن
آخرين xبر روی سطر تطبیق ميکند.
دو چیز مهم قابل توجه در مورد ستبارها وجود دارند .روی اينکه ،ستبار فقط برای يك کاراکتر بکار ميرود ،بنابراين * xyيك xرا که
با y’sدنبال ميشود تطبیق ميکند نه يك توالي مانند . xy xy xyدوم اينکه ،هر عددی شامل صفر ميباشد ،بنابراين اگر شما بخواهید
که حداقل يك کاراکتر را تطبیق کنید ،شما بايد آن را دو نسخهای کنید .برای مثال ،برای تطبیق يك رشته از حروف ،عبارت صحیح [a-
]ZA-Z[ * ]a – ZA – Zميباشد [ يك حرف يا چند حرفي که با Zدنبال ميشوند]. اسم فايل شل * که کاراکتر را تطبیق ميکند ،شبیه به عبارت منظم * .ميباشد.
هیچ گونه عبارت منظم ،grepيك سطر جديد را تطبیق نميکند؛ عبارتها برای هر سطر به طور جداگانه بکار ميروند.
با عبارت منظم grep ،يك زبان برنامهنويسي ساده ميباشد .برای مثال ،به خاطر بیاوريد که دومین میدان فايل کلمه رمز ،رمزی کردن
کلمه رمز ميباشد .اين فرمان بدون کلمات رمز برای کاربرها به جستجو ميپردازد:
$ grep ′^ ] ^ :[ * : : ′ / etc / passwd اين طرح به اين صورت است :آغاز سطر ،هر عدد بدون دو نقطه ،دو نقطه دوبل ، grepدر حقیقت ،قديميترين خانواده از برنامهها ميباشد ،ساير اعضاء آنـ Fgrepوـ egrepنامیده ميشوند .رفتار اصلي آنها شبیه به هم است ،اماـ fgrepبه جستجوی بسیاری از
رشتههای حرفي به طور همزمان ميپردازد ،در حالیکه egrepعبارتهای منظم درست را تفسیر ميکند ـ همانند ، grepاما با يك عملگر
orو پرانتزها برای گروه بندی کردن عبارتهايي که در زير شرح داده ميشوند.
هم fgrepو هم ، egrepهر دو برای مشخص کردن يك فايل که از آن طرح را بخوانند انتخاب – fرا ميپذيرند .در فايل ،سطرهای جديد ،طرحهايي را که بايد مورد جستجو قرار بگیرند به طور موازی از هم جدا ميکنند .اگر کلماتي باشند که شما بر حسب عادت به
طور تلفظ ميکنید ،شما ميتوانید اسناد خود را برای چنین رخدادی ،با حفظ آنها در يك فايل ،درهر سطر و با استفاد از fgrepکنترل کنید :
$ fgrep - f common – errors document عبارتهاي منظم تفسير شده توسط ( egrepكه در جدول ۴.۱نيز فهرست وار وجود دارند) شبيه عبارات موجود ، grepبا دو مورد اضافه ميباشند .پرانتزها ميتوانند براي گروهبندي كردن استفاده شوند ،بنابراين ( *) x yهر رشته خالي را تطبيق ميكندxy ، xy xy ، xy ، xy xyو به همين ترتيب .نوار عمودي | يك عملگر" " orميباشد; - today | tommorowامروز يا فردا را تطبيق ميكند همانند . )to )day | morrowدر آخر اينكه دو عملگر ستبار ديگر در egrep
محیط برنامه سازی لینوکس
96/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و egrep
(به ترتیب تقدم)
هر کاراکتر غیر ويژه ،cخودش را تطبیق ميکند
c
هر معني ويژهای از کاراکتر cرا خاموش ميکند
\c
آغاز سطر
^
پايان سطر
$
هر کاراکتر مفرد
0
هر يك از کاراکترها در … قرار دارند ؛ مراتبي مانند a-zمجاز هستند
[…]
هر کاراکتری که در … قرار ندارد؛ مراتب مجاز هستند.
[ ^ …]
چیزی که )\ …( \ n’ thتطبیق ميشود (فقط (grep
\n
صفر يا چند رخداد از r
*r
يك يا چند رخداد از ( rفقط (egrep
+r
صفر يا يك رخداد از ( rفقط (egrep
?r
r1با r2دنبال ميشود r1يا ( r2فقط (egrep عبارت منظم و دارای علمت ( rفقط )grep؛ ميتواند تودر تو ساخته شود عبارت منظم ( rفقط )egrep؛ ميتوند تو در تو ساخته شود
r1r2 r1 | r2
\ ()\r () r
هیچ عبارت منظمي يك سطر جديد را تطبیق نميکند.
تمرين .۱-۴عبارات منظم دارای علمت ( (\ ( ) | )andرا در ضمیمه ۱يا ( ed )۱پیدا کنید و از 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آغاز سطر است .بنابراين ،برای مثال،
با شمارش بايت ،از بزرگترين مرتب ميشود با زمان ، loginاز قديميترين مرتب ميشود
$
s - 1 | sort + 3 nr / who | sort + 4n $
ساير انتخابهای مفید 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ميرويم .چون 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
18 ch 4. 1 13 ch 4. 2 14 ch 3. 4 17 ch 4. 4 2 ch 4. 9 $ شما ميتوانید از sedبرای کنار گذاشتن (حذف) بخش اندازه استفاده کنید ،اما فرمان ويرايش نیازمند نقل قولها برای محافظت از يك * و يك جدول از تفسیر شدن توسط شل ميباشد :
ch 4. * | sed ′ s / . * → // ′
$ du – a ch 4.1 ch 4.2 ch 4.3 ch 4.4 ch 4.9 $
جايگزيني همه كاراكترهاي ( * )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انجام داد :
′s/^/→/
sed 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 / $ / >/′
يك سطر جديد را به انتهاي هر سطر اضافه ميكند ،در نتيجه فاصله دوبل به ورودي آن اضافه ميشود و
′ s / ] →[ ]→ $
\ / * ]sed <g′/
هر رشته از فاصلههاي خالي يا جدولبنديها را با يك سطر جديد جايگزين ميكند و در
محیط برنامه سازی لینوکس
104/322
نتيجه ورودي خود را در يك كلمه در هر سطر ،تقسيم ميكند( .عبارت منظم ' [→] ' ،يك فاصله يا جدولبندي را تطبيق ميكند ؛ ‘ [→] * ' تعداد صفر يا چند تا از اين فاصلهها يا جدولبنديها را تطبيق ميكند ،بنابراين كل طرح يك يا چند فاصله و يا چند جدولبندي را تطبيق ميكند. همچنین شما ميتوانید جفتهايي از عبارات منظم يا شمارههای سطر را برای انتخاب يك دامنه از سطرهايي بکار ببريد که بر روی آنها يکي از فرمانها عمل ميکنند.
فقط از ۲۰تا ۳۰سطر را پرينت كنيد
- n ′ 20 , 30 p′ $
سطرهاي ۱تا ۱۰را حذف كنيد (tail =( +11
′ 1 , 10 d ′
تا جايي حذف كنيد كه فقط يك سطر خالي باشد هر گروه از سطرها را از يك سطر خالي
$ sed
′ 1 , /^ $/ d ′
$
sed
sed
sed - n ′ / ^ $ / , / ^ end / p′ $
تا سطري كه با endآغاز ميشود پرينت كنيد آخرين سطر را حذف كنيد.
$
′$d′
sed
شمارههای سطر از آغاز ورودی ميآيند؛ آنها در آغاز يك سطر جديد رسیت نميشوند .اما يك محدوديت مهم از sedوجوددارد که
مشترك با edنميباشد :شمارههای نسبي سطر حفظ نميشوند .بويژه + ،و … در عبارتهای شماره سطر درك نميشوند ،بنابراين،
رسیدن به عقبروها در ورودی امکانپذير نميباشد.
نميتواند به عقب رو استناد شود :غيرمجاز
$
sed ′ $ - 1 d ′ dفرمان شناسايي نشده 1 - $ : $
زماني که يك سطر خوانده ميشود ،سطر قبلي برای همیشه پاك ميشود :هیچ راهي برای شناسايي سطر بعد از قبلي وجود ندارد، يعني چیزی که اين فرمان نیاز دارد( .به طور عادلنه ،يك راه برای کارکردن آن با sedوجود دارد ،اما اين راه خیلي پیشرفته است .به
فرمان « »holdدر کتاب راهنما مراجعه کنید) .همچنین راهي برای انجام نشاني دهي نسبي به طرف جلو وجود ندارد:
نميتواند به جلورو استناد شود :غیر مجاز
، sedتوانايي خواندن بر روی فايلهای خروجي متعدد را فراهم ميکند .برای مثال ،
sed ′ / thing / + d′
′ / pat / w file / … / pat / ! w file r′ filenames
sed – n
$ $
سطرهايي را مينويسد که patروی فايل 1را تطبیق ميدهند و سطرهايي که patروی فايل ۲را تطبیق نميدهند .يا برای مشاهده مجدد اولین مثال ما ،
محیط برنامه سازی لینوکس
105/322
sed ′ s / unix / unix )Tm( / gw u.04 t ′ filenames … > output کل خروجي را برای خروجي فايل همانند قبل مينويسد ،اما همچنین فقط سطرهای تغییر يافته برای فايل u .outرا نیز مينويسد.
$
گاهي اوقات ،همکاری با شل برای قرادادن آرگومانهای فايل شل در وسط يك فرمان sedلزم است .يك مثال در اين خصوص ،برنامه
newerميباشد که همه فايلهايي را در يك فهرست لیست ميکند که جديدتر از فايلهای خاص ميباشند.
$ cat newer # newer f : list files newer than f Is – t : sed ′ / ^ ′ $ | ′ $ / q′ $
نقل قولها ،از کاراکترهای خاص و متعدد هدف دار در sedمحافظت ميکنند؛ زماني که در معرض حذف 1 $قرار ميگیرند ،در نتیجه
شل آن را با اسم فايل جايگزين ميکند .يك روش ديگر برای نوشتن آرگومان به اين شکل ميباشد :
″/^$|\$q″ چون / $با آرگومان جايگزين ميشود زماني که \ $فقط به $تبديل ميشود .به همین روش ،ما ميتوانیم olderرا بنويسیم که همه
فايلهای قديميتر از فايلهای نامگذاری شده را لیست ميکند :
$ cat older # older f : list files older than f Is – tr | sed ′ / ^ ′ $ | ′ $ / q′
تنها تفاوت انتخاب - rبر روی ISبرای معکوس کردن ترتیب ،ميباشد.
جدول : ۴.۲ خلاصه فرمانهاي sed سطرها را تا جايي به خروجي پيوست ميدهد كه هيچ سطري با \ به پايان نرسد \a
/ b /abe انتقال به فرمان abe// : \c سطرها را به متن بعدي به صورت aتغيير ميدهد d سطر را حذف ميكند؛ سطر ورودي بعدي را مي خواند i/ متن بعدي را قبل از خروجي بعدي اينسرت ميكند. سطر را فهرستبندي ميكند ،همه كاراكترهاي غير پريتر را مرئي ميكند l p سطر را پرينت ميكند q از سيستم خارج ميشود r file فايل را ميخواند ،محتواهاي آن را براي خروجي كپي ميكند s / old / new / f Newرا با oldجايگزين ميكند .اگر ،f = gهمه رخدادها را جايگزين ميكند ؛ . f = pپرينت ميكند؛ ، f = wfile فايل را ميخواند. امتحان :انقال به /abp/انجام ميشود اگر جايگزيني براي سطر خللي انجام شود. /t /abe wfile سطر را براي فايل مينويسد /y / strl / str 2 هر كاراكتر از strlرا با كاراكتر مطابق از str2جايگزين ميكند (مراتب مجاز نيستند)
شماره سطر ورودي فعلي را پرينت ميكند sed cmdرا انجام ميدهد فقط اگر سطر انتخاب نشود / abe /را براي فرمانهاي bو tتعيين ميكند
= ! cmd / abe / :
محیط برنامه سازی لینوکس
106/322
فرمانها را تا تطبيق } به عنوان يك گروه بررسي ميكند
}
اگرچه ،sedخیلي بیشتر از چیزهايي که شرح داديم انجام ميدهد ،شامل بررسي شرايط ،حلقهسازی و منشعب کردن ،به خاطر آوردن
سطرهای قبلي و البته بسیاری از فرمانهای edکه در ضمیمه ۱توصیف ميشوند ـ اما قسمت اعظم استفاده ،sedشبیه به چیزی است که
ما در اين جا نشان دادهايم ـ يك يا دو فرمان ساده ويرايش ـ و چیزی غیر از تواليهای بلند يا پیچیده ميباشد .جدول ، ۴.۲برخي از
تواناييهای sedرا به طور خلصه بیان ميکند ،اگر چه ،عملکردهای چند سطری در اين جدول حذف است.
Sedمناسب و آسان است چون به صورت اختیاری مي تواند با ورودیهای بلند کار کند ،چون سريع است و چون شبیه به edبا
عبارتهای منظم و پردازش يك سطر در يك زمان آن ميباشد .اما روی ديگر سکه sed ،ـ يك شکل نسبتا محدود از حافظه را فراهم ميکند (به خاطر آوردن متن از يك سطر تا سطری ديگر دشوار است) sed ،فقط يك عبور از دادهها را امکانپذير ميسازد ،برگشتن به
عقب امکان پذير نميباشد ،راهي برای انجام ارجاعات به سمت جلو مانند ، / … / +1وجود ندارد و sedتسهیلتي را برای کار کردن با شمارهها فراهم نميکند ـ sedصرف ًا يك ويراستار متن ميباشد.
تمرين Older .۴. ۵و Newerرا به گونهای تغییر دهید که ديگر دارای فايل آرگومان در خروجي خود نباشند .آنها را به گونهای تغییر دهید که فايلها در يك ترتیب مخالف فهرستبندی شوند.
تمرين .۴.۶از sedبرای استحکام bundleاستفاده کنید .توجه :در اسناد موجود در اينجا ،کلمه نشان پايان ،فقط زماني شناسايي ميشود که سطر را به طور دقیق تطبیق کند.
۴.۴پويش طرح awkو زبان پردازش
برخي از محدوديتهايت ، sedتوسطت awkبرطرف ميشوند .طرح مربوط بهت ، awkتا حدود زيادي شبيه بهت sedميباشد ،اما جزئيات آن بيشتر بر اساس زبان برنامهنويسي cمي $ باشند تا يك ويراستار متن .استفاده از awkدرست شبيه به sedميباشد : …awk ′program′ filenames اما برنامه متفاوت است :
{ pattern } action { pattern } action … ،awkورودی را در اسامي فايل ،در هر زمان يك سطر ،ميخواند .هر فايل با هر طرح به اين ترتیب مقايسه ميشود؛ برای هر طرحي که سطر را تطبیق ميکند ،عملکرد مطابق با آن انجام ميشود awk .همانند ، sedفايلهای ورودی خو درا تغییر نميدهد.
طرحها ميتوانند عبارتهای منظم ،دقیقاً مانند عبارتهای egrepباشند ،يا ميتوانند دارای شرايط پیچدهتر و يادآور cباشند .به عنوان يك مثال ساده ،اگر چه
… ′/ regular expressino / } print{ ′ filenames اما کاری را انجام ميدهد که egrepانجام ميدهد :اين عبارت هر سطری را پرينت ميکند که عبارت منظم را تطبیق ميکند.
awk
$
طرح يا عملکرد انتخابي ميباشند .اگر عملکرد حذف شود ،عملکرد پیش فرض سطرهای تطبیق شده را پرينت ميکند ،بنابراين … ′ / regular expression / ′ filenames
$ awk
محیط برنامه سازی لینوکس
107/322
همان کاری را انجام ميدهد که مثال قبلي انجام ميدهد .به طور معکوس ،اگر طرح حذف شود .در نتیجه بخش عملکرد برای هر سطر ورودی انجام ميشود .بنابراين
… ′} print{ ′ filenames
چیزی را انجام ميدهد که catانجام ميدهد ،ولو اينکه کندتر انجام ميدهد.
awk
$
و اما نکته نهايي ،قبل از اينکه به مثالهای جالب بپردازيم .همانند ،sedاين امکان وجود دارد که برنامه را برای awkاز يك فايل ارائه
دهیم :
filenames ….
awk – f cmd file
$
ميدانها awkبه طور خودکار هر سطر ورودی را به میدانها تقسیم ميکند ،يعني رشتههايي از کاراکترهای بدون فاصله که توسط فاصلهها يا جدولبندیها از هم جدا ميشوند .با اين تعريف ،خروجي whoدارای پنج میدان ميباشد :
11 : 35 11 : 27
sep 29 sep 29
tty 2 tty 4
who you jim
$
$ awkمیدانهای $2 ، $1و … ، NF $را ميخواند NF ،متغیری است که ارزش آن برای تعداد میدانها معین ميشود .در اين مورد ،
NFبرای هر دو سطر ۵ميباشد ( .به تفاوت بین ، NFعداد میدانها و ،$ NFيعني آخرين میدان بر روی سطر توجه کنید .در ،awk بر خلف شل ،فقط میدانها با يك $آغاز ميشوند؛ متغیرها ساده هستند) .برای مثال ،برای جدا کردن اندازههای فايل ايجاد شده توسط
du-a و برای پرينت اسامي افراد وارد شده به سیستم و زمان ، loginدر يك سطر :
du – a | awk ′ } print $ 2 {′ who | awk ′ } print $ 1 , $ 5 {′ you 11 : 53 jim 11 : 27
برای پرينت نام و زمان loginترتیب بندی شده توسط زمان :
′ } print $ 5 , $ 1 {′ | sort
who | awk
$ $ $ $
11 : 27 jim 11 : 53 you $ راهکارهای ديگری برای نسخههای sedوجود دارند که قبل در اين فصل ارائه شدند .اگر چه awkآسانتر از sedبرای عملکردهايي
مانند اينها ،قابل استفاده ميباشد ،اما معمولً کندتر است و هر دو آغاز به کار و اجرا ميکنند زماني که ورودی زيادی وجود دارد awk .
در حالت عادی به صورت فضای سفید (هر تعداد از فاصلهها يا جدول بندیها) ،میدانهای مجزا ،تصور ميشود ،اما جداساز ميتواند
برای هر کاراکتر مفرد تغییر کند .يك روش برای تغییر ،انتخاب سطر فرمان ( -Fمورد باليي) ميباشد .برای مثال ،میدانهای موجود در
محیط برنامه سازی لینوکس
108/322
فايل کلمه رمز ، 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از ابتدا در اين فصل) را به صورت زير بنويسیم که يك جدولبندی ( )\ tو رکورد ورودی را چاپ ميکند.
* awk ′ } print f ″ \ t % s \ n ″ , $o { ′ $
محیط برنامه سازی لینوکس
109/322
طرحها فرض کنید شما ميخواهید به عبارت etc / passwd /در جستجوی افرادی باشید که دارای هیچ گونه کلمه رمزی نميباشند .کلمه رمز
رمزی شده ،دومین میدان ميباشد ،بنابراين برنامه ،فقط يك طرح ميباشد :
$ awk – f : ′ $ 2 = = ″ ″ ′ / etc / passwd طرح درخواست ميکند که آيا دومین میدان ،يك رشته خالي است ( ‘ = = ’ ،عملگر تست تساوی ميباشد) شما ميتوانید اين طرح را
به روشهای متعدد بنويسید :
دومين ميدان خالي است دومين ميدان ،رشته خالي را تطبيق ميكند دومين ميدان هيچ كاراكتري را تطبيق نميكند طول دومین میدان صفر است
″ ″==2 $ /$^/∼2 $ /./ ∼!2 $ = = )0length )$ 2
علمت ، تطبيق عبارت منظم را نشان ميدهد و به ! به معناي « تطبيق نميكند» ميباشد .عبارت منظم خودش ضميمه اسلشها ميشود. ، lengthيك عملکرد توکار از awkميباشد که طول يك رشته از کاراکترها را بوجود ميآورد .يك طرح ميتواند به دنبال ! برای
منفي کردن آن بیايد ،مانند
‘!’ يك عملگر شبیه cميباشد ،اما برخلف sedميباشد ،چون در آنجا ! پس از طرح ميآيد.
(! ) $ 2 = = ″ ″
يکي استفاده عمومي از طرحها در ، awkبرای وظايف مربوط به معتبرسازی دادههای ساده ميباشد .بسیاری از اين وظايف ،اندکي بیشتر از جستجوی سطرهايي ميباشند که معیار خود را از دست ميدهند؛ اگر هیچ گونه خروجي وجود نداشته باشد .دادهها قابل قبول
هستندـ (هیچ خبری ،خبر خوبي نیست) .برای مثال ،طرح زير ،اطمینان ميدهد که هر رکورد ورودی که دارای تعدادی از میدانها ميباشد ،از عملگر %برای محاسبه باقیمانده ،استفاده ميکند:
# print if old number of fiflds ديگری ،سطرهای بیش از حد طولني را ،با استفاده از عملکرد lengthتوکار چاپ ميکند :
!=0
NF % 2
/ 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
1983
$ date Thu sep 29 12 : 17 : 01 EDT
محیط برنامه سازی لینوکس
110/322
$ date | awk ′ } print substr ) $ 4 , 1 , 5( {′ 12 : 17 $ تمرين .۴.۷چند برنامه awkميتوانید بنويسید که ورودی را برای خروجي همانند کاری که catانجام ميدهد ،کپي کنند؟ کدام يك کوتاهترين ميباشد ؟
طرحهاي END , BEGIN ، awkدو طرح خاص را بوجود ميآورد،ـ BEGINوـ . ENDعملکردهایـ BEGINقبل اينکه سطر ورودی خوانده شود ،اجرا ميشوند ؛ شما ميتوانید از طرح BEGINبرای آغاز متغیرها ،برای چاپ عنوانها و يا برای تعیین جداساز میدان با نسبت دادن آن به متغیر FSاستفاده کنید :
{ ′ BEGIN } FS = ″ : ″ $2 = = ″ ″ ′ / etc/passwd
ما از همه رمزهاي عبور استفاده ميكنيم :خروجي ندارد
$ awk >
$
عملكردهاي ، ENDپس از پردازش آخرين سطر ورودي ،انجام ميشوند : … ′ END } print NR{ ′
awk
$
تعداد سطرهاي ورودي را پرينت ميكند. حساب و متغیرها
مثالهايي که تاکنون بیان شدهاند ،فقط به استفاده در متن ساده پرداختهاند .قدرت واقعي ،awkمربوط به توانايي آن برای انجام محاسبات
بر روی دادههای ورودی ميباشد ؛ شمردن چیزها ،محاسبه مجموعهها و میانگینها و مواردی از اين قبیل آسان است .يك استفاده
عمومي از ،awkجمع کردن ستون اعداد ميباشد.
برای مثال ،برای جمع کردن همه اعداد در اولین ستون :
{}s=s + $1 { } prints چون تعداد ارزشها در متغیر NRدر دسترس ميباشد .در نتیجه آخرين سطر را به شکل زير تغییر ميدهیم که هم مجموع و هم میانگین را چاپ ميکند.
{ } print s , s / NR
END END
اين مثال ،استفاده از متغیرها در 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را در انتهای يك سطر تطبیق نميدهد.
سر راست ميشود.
1.4 2.4 3.4 4.4 9.4
ch ch ch ch ch
كل
براي
18129 13242 13455 16904 117 62847
$
* wc ch 4. 753 3090 612 2124 637 2462 802 2986 50 213 2854 11172 * $ prpages ch 4. 53 $
اين نتيجه pr ،را در awkمستقيما اجرا كنيد : | awk ′ End } print NR / 66{′
*pr ch 4.
$ 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
نام فايل ورودی فعلي
FILENAME
کاراکتر جداساز میدان ( پیش فرض فاصله و جدول بندی)
FS
تعداد میدانها در رکورد ورودی
NF
تعداد رکورد ورودی
NR
فرمت خروجي برای اعداد (پیش فرض % gو به ( printf )۳مراجعه کنید
رشته جداساز میدان خروجي (پیش فرش فاصله)
رشته جداساز ثبت خروجي ( پیش فرض سطرجديد)
کاراکتر جداساز ثبت ورودی ( پیش فرض سطر جديد )
OFMT OFS ORS RS
جدول : ۴.۴علمگردهای ( awkبه ترتیب افزايش تقدم)
تخصیص؛ V= Vop , expr = Vopميباشد )
هر کدام باشد صحیح است or : exprl || expr 2
= + = - = * = / = % = ) )expr | |
محیط برنامه سازی لینوکس
114/322
expr 2ارزيابي نميشود اگر exprصحیح باشد
AND : expr 1 $ $ expr 2اگر هر دو باشند ،صحیح است
$ $
expr 2ارزيابي نميشود اگر expr 1اشتباه باشد ارزش عبارت را منفي ميکند
هاي ؛ و ! ، عملگرهاي رابط
! ≈! ≈
==>>= < <
تطبیق هستند و پیوند دهي رشته را تطبیق نميکنند.
به اضافه ،منها
+ -
ضرب ،تقسیم ،باقیمانده
%
افزايش ،کاهش (پیشوند يا پسوند )
\ *
+ + - -
آرايهها ،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 کسینوس expr
)cos)expr
تابع نمايي expr: eexpr
) exp )pxpr
سطر ورودی بعدی را ميخواند :صفر را برميگرداند اگر پايان فايل باشد اگر پايان فايل نباشد 1 ،را بر ميگرداند
موقعیت رشته S2در :s1اگر آشکار نشود صفر را بر ميگرداند ميکند
) ( get line
)index)s1,s2بخش صحیح expr؛ به طرف صفر سر راست
)int)expr
طول رشته s
)length )s
لگاريتم طبیعي expr
)log )expr
سینوس expr
)sin )expr
تقسیم sبر ] [ ]n a … ]1روی کاراکتر c؛ ( s ,a,c( split nرا بر ميگرداند . فرمت … بر طبق ويژگي fmt
sprint f)fmt
)…,
آرايههاي انجمني يك مشکل استاندارد در پردازش دادهها ،جمعآوری ارزشها برای يك مجموعه از جفتهای نام /ارزش ميباشد .چنین چیزی از ورودی به صورت زير است.
400 100 200 300 100 100 100
susie John Mary Mary John Susie Mary
محیط برنامه سازی لینوکس
116/322
ما ميخواهیم ارزش کل را برای هر نام محاسبه کنیم:
John 200 Mary 600 Susie 500 ، awkيك روش موثر را برای انجام اين کار فراهم ميکند ،آرايه انجمني .اگر چه فرد در حالت عادی زيرنويسهای آرايه را به عنوان اعداد صحیح تصور ميکند ،اما در awkهر ارزش ميتواند به عنوان يك زيرنويس استفاده ميشود .بنابراين
[]sum]$1[+=$2 }for )name in sum( print name , sum ]name
}]END
يك برنامه کامل برای جمع کردن و چاپ کردن مجموع جفتهای نام -ارزش همانند موارد مذکور در بال ميباشد ،حال چه آنها
ترتیب بندی شوند و چه نشوند.
هر نام ( )$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
" " Blanks = blanks { } (if )n = lingth )$o( <=n print }else {(for ) I=1, n>N,n-=N
(printf " % s \\\n" , substr)$o, i,N
i t=N, { (printf " s%s \n", substr )blanks , 1 ,N –n(, substr)$O,i { '{ در awkعملگر پیوند دهي رشته به صورت آشکار وجود ندارد؛ رشتهها به هم محلق ميشوند ،زماني که آنها هم جوار هستند .در ابتدا،
blanksيك رشته تهي ميباشد .حلقه در بخش ، BEGINيك رشته بلند از blankها را ازطريق پیوند دهي بوجود ميآورد:
هر حرکت در اطراف حلقه ،يك blankديگر به انتهای blankها اضافه ميکند .دومین حلقه سطر ورودی را در chunkها پردازش ميکند تا جايي که بخش باقیمانده به میزان کافي کوتاه ميباشد .همانند ، Cبیان تخصیص ميتواند به عنوان يك عبارت استفاده شود، بنابراين ساخت
…(If ))n = 1ength)$o(( <=N طول سطر ورودی به nاختصاص ميدهد قبل از اينکه ارزش را آزمايش کند ،به پرانتزها توجه داشته باشید.
تمرين 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امین میدان اضافه ميکند:
محیط برنامه سازی لینوکس
سومین مثال ،مجموعهای مجزايي را از هر کدام از ستونهای -nهمراه با مجموع کل تشکیل ميدهد:
119/322
{'awk' } s += $' $ 1 '{END }print s
'awk {'BEGIN}n = ' $ 1 } (for )i=1 ,i <n, I+t sum ]i[ t = $I { } END }(for )i=1 , i <=n, , i+t [Printf " % 4g " , sum]i { printf " , total = % 4g \ n " , total '{ ما از BEGINبرای درج ارزش nدر يك متغیر استفاده ميکنیم ،به جای اينکه مابقي برنامه را با نقل قولها دستهبندی کنیم. مشکل عمده با همه اين مثالها ،نگهداشتن رد چیزی نیست که در داخل يا خارج از اين نقل قولها ميباشد( اگر چه ،يك دردسراست)، بلکه همانگونه که اخیر ًا نوشته شده است ،اين برنامهها ميتوانند فقط وردی استاندارد خود را بخوانند ؛ راهي برای عبور آنها ،هم پارامتر
nو هم يك فهرست باند اختیاری از اسامي فايلها وجود ندارد چنین چیزی نیازمند برنامهنويسي شل ميباشد که ما در فصل بعد به آن ميپردازيم.
يك سرويس تقويم بر اساس awk مثال اخیر ما از آرايههای انجمني استفاده ميکند ؛ همچنین يك شرح از چگونگي بر هم کنش با شل وجود دارد و تا حدودی در مورد
ارزيابي برنامه ،شرح ميدهد.
وظیفه ،اين است که سیستم هر روز صبح پستي را برای شما بفرستد که شامل يك تقويم از وقايع آينده باشد .ممکن است چنین
سرويس تقديمي وجود داشته باشد ؛ به )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
{(for )i=1 , I )24 , I t=2 [days ]data]i[ [=data]i+1 [next mon ]dafa]i[[=data]I+2 { (split )" , " \ date ‘ " , " , date [mon / = date ]2[ , day / = date ]3 mon2= mon/, day 2 = day 1+1 {( [if)day( > = days ]mon1 day 2 =1 [mon 2=next mon ] mon1 { $ 1 = = mon 1 $ $ $2 = = day || $1 = = mon 2 $ $ $2 = = day 2 | mail $ NAME $ توجه داشته باشید که Janدر يك داده دوباره ظاهر ميشود ؛ يك ارزش داده« اشاره نما » مانند اين ،پردازش را برای دسامبر آسان ميکند.
مرحله نهايي ،مرتب کردن برنامه تقويم به گونهای ميباشد که هر روز اجرا شود .چیزی که شما ميخواهید اين است که هر روز صبح
حدود ساعت ۵صبح از خواب بیدار شويد و calendarرا اجرا کنید .شما ميتوانید اين کار را با به خاطر آوردن برای sayخودتان
انجام دهید ( هر روز !)
$ at 5am calendar ct1-d $ اما چنین چیزی دقیقاًـ قابل اعتماد يا خودکار نميباشد .ترفند اين است کهـ atرانه فقط برای اجرای تقويم ،بلکه همچنین برای برنامهريزی اجرای بعدی نیز بیان کنیم.
$ cat early .morning calendar echo early . morning | at 5 am $ دومین سطر ،فرمان atديگری را برای روز بعد ،برنامهريزی ميکند ،در نتیجه زماني که شروع ميشود ،اين توالي ،به صورت دائمي
مي باشد .فرمان ، at PATHشما را و نیز فهرست جاری و ساير پارامترها را برای فرمانهايي که پردازش ميکند ،تعیین ميکند، بنابراين شما نبايد کار خاصي انجام دهید.
تمرين . ۴-۱۱تقويم را به گونهای تغییر دهید که در خصوص آخر هفتهها نیز بداند .در جمعه« ،فردا» شامل شنبه ،يکشنبه و دوشنبه
ميباشد .تقويم را به گونهای تغییر دهید که به صورت پرشي از سال استفاده کند .آيا تقويم در خصوص تعطیلتها بايد چیزی ميداند؟
چگونه آن را مرتب ميکنید؟
تمرين . ۴-۱۲آيا تقويم در خصوص تاريخهای موجود در يك سطر بايد بداند ،نه فقط در آغاز سطر؟ در خصوص تاريخهای ارائه
شده در ساير فرمتها مانند ۱۰/۱/۸۳چطور؟
تمرين .۴-۱۳چرا تقويم به جای $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
فصل پنجم :برنامهریزي پوسته باوجود آنکه اکثر کاربران پوسته را يك عنصر فرمان تبادلي ميشمارند ،اما در واقع نوعي زبان برنامهنويس است که در آن هر عبارت
فرماني را اجرا ميکند .از آنجا که بايد هر دو زمینه تبادلي و برنامهريزی اجرای دستور را ،تأمین کند ،يك زبان غیرعادی است که بیشتر با تاريخچة شکل گرفته تا با طرح .محدودة کاربرد آن ،حجم نابساماني از جزيیات در زبان برنامهنويسي را به همراه دارد .اين فصل،
مباني برنامهريزی پوسته را به همراه نشان دادن سیر تکامل برخي برنامههای پوسته ،تشريح خواهد کرد ،اما بايد توجه کرد که راهنمايي
برای پوسته نیست ،چنین چیزی در صفحة راهنمای ( sh)1از راهنمای برنامه نويسان يونیکس ،که بايد همواره در حین خواندن کتاب، آنرا در دسترس داشته باشید ،يافت ميشود.
همچون اکثر دستورات ،در پوسته نیز يافتن جزيیات رفتار برنامه ،به سرعت و باتجربه ،تحقق مييابد .راهنمای استفاده ميتواند پیچیده باشد ،اما هیچ چیز برای درك مسايل ،بهتر از يك مثال مناسب نیست .بدين منظور ،اين فصل بیشتر حول مثالها متمرکز شده تا
ويژگیهای پوسته و راهنمايي است جهت استفاده از پوسته برای برنامهنويسي ،نه فقط دايرهالمعارفي از توانائيهای آن .ما تنها در مورد آنچه پوسته ميتواند انجام دهد ،صحبت نميکنیم ،بلکه در مورد توسعه و نوشتن برنامههای پوسته ،با تأکید بر آزمايش و تبادل نظرات آزمايشي نیز سخن به میان ميآوريم.
هنگامي که شما يك برنامه را نوشتهايد ،در پوسته يا در هر زبان ديگر ،ممکن است استفاده از آن توسط ساير افراد به قدر کافي مفید
باشد ،اما استانداردهايي که سايرين از يك برنامه انتظار دارند ،معمول ً موشکافانه تر از استانداردهای شخص است که در مورد خود به کار ميگیرد .نمای کلي در برنامهنويسي پوسته نیرومند کردن برنامهها به گونه ايست که بتوانند ورودی غیرصحیح را منتقل کرده و به
هنگام غلط بودن مواردی ،اطلعات مفیدی ارايه دهند. . ۵.۱سفارشي کردن دستور cal
يکي از استفادههای معمول برنامة پوسته ،اصلح يابهبود ارتباط کاربر با برنامه است .به عنوان مثالي از يك برنامه که بهبود را نشان دهد، به فرمان ( cal)1را توجه کنید:
Good so far Not so good
$ cal usage: cal ]month[year $ cal october 1983 bad argument $ cal 10 1983 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 $
محیط برنامه سازی لینوکس
126/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واقعي را فراخواني ميکند .متغیر پوستة ، $#تعداد آرگومانهايي را که يك فايل پوسته با آنها فراخواني ميکند ،درخود نگهداری ميکند ،ساير متغیرهای خاص پوسته ،در جدول ۵-۱فهرست شدهاند.
)0 )1
$ cat cal $ cal: nicer interface to /use/bin/cal case $ # in # ;; set `date` ; m=$2; y=$6هیچ آرگوماني موجود نیست :از امروز استفاده ميشود # ;; m=$1; set `date`; y=$6يك آرگومان :از امسال استفاده مي شود دو آرگومان :ماه و سال #
;; m=$1; y=$2
;; ;; ;; ;; ;;
m=1 m=2 m=3 m=4 m=5
(*
esac casc $m in (*jan*|Jan (*feb*|Feb ( * mar * | Mar (* apr * | Apr (*may * | May
محیط برنامه سازی لینوکس
127/322
(*jun* | Jun (*jul* | Jul (*aug* | Aug (*sep* | sep (*oct* | oct (*nov* | Nov (*dec*| Dec ;; (]1-9[ | 10 |11|12
;; m=6 ;; m=7 ;; m=8 ;; m=9 ;; m=10 ;; m=11 ;; m=12 ماه به عدد #
سال عادی y=$m; m= '' '' ;; #
(*
esac /usr/bin/cal $m $y
تقويم واقعي اجرا ميشود #
اولین عبارت تعداد آرگوماني را بررسي ميکند ، $ # ،و عملکرد مناسب را انتخاب ميکند .نمونة * انتهايي در caseاول : catch-all
اگر شمارة آرگومان نه صفر باشد و نه يك ،آخر عبارت اجرا خواهد شد( .از آنجايي که نمونهها به ترتیب جاروب ميشوندcatch-all ،
بايد آخرين باشد ).اين امر y,mرا برای ماه و سال انتخاب ميکند ـ دو آرگومان داده شده و calما همانند نمونة اصلي عمل خواهد
کرد.
اولین عبارت
`Set `date
، caseدارای يك جفت خط پیچیده شامل
است .باوجود اينکه از ظاهر آن مشخص نیست ،اما ميتوان به سادگي با آزمايش کردن آن دريافت که اين عبارت چه عمل انجام ميدهد:
جدول : ۵.۱متغیرهای دروني پوسته
تعداد آرگومانها
$#
تمامي آرگومانهايي که وارد پوسته ميشوند
*$
مشابه * $؛ بخش ۵-۷را ببینید
@$
گزينههايي که برای پوسته فراهم شدهاند.
$-
مقدار بازگشتي آخرين فرمان اجراشده
?$
شناسايي فرآيند پوسته
$$
شناسايي فرآيند آخرين فرماني که با & آغاز شده
!$
آرگومان پیش فرض برای فرمان cd
$Home
فهرست کاراکترهايي که کلمات را در آرگومانها از هم جدا ميکنند
$ IFS
فايلي که هنگام تغییريافتن ،پیغام “ ”you have mailرا فعال ميکند.
$ MHJL
فهرست دايرکتوريهای جستجوی فرامین
$ 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را جزء به جز تطبیق ميدهد.
تنها در عبارات a,caseيا bرا تطبیق ميدهد در نام فايلها ،آنهايي را که فقط با يك /در عبارات ،تطبیق داده شدهاند؛ در case
هرکدام که مانند ساير کاراکترها مطابقت دارند .
به عنوان اولین کارکتر نام يك فايل ،فقط با يك 0در عبارت تطابق دارد.
"…" \c a|b / 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 $
و ، cal ۱۹۸۴تقويم را برای کل ۱۹۸۴چاپ ميکند.
برنامه calارتقا يافتة ما ،همان کار را مانند نمونة اصلي انجام ميدهد اما با يك روش سادهتر و قابل حفظتر .از اين رو آنرا بیشتر cal
ميخوانیم تا ( calendarکه يك دستورات) يا چیزی که کمتر به ياد ميماند مانند . ncalتنها نهادن اين نام ،اين خوبي را دارد که
کاربران نیاز به توسعه و افزايش بازتابهايي را جهت چاپ تقويم ،ندارند.
پيش از آنكه از caseبگذريم ،بهتر است به خلصهاي از اين موضوع بپردازيم كه چرا قوانين تطبيق نمونهها در پوسته متفاوت از آنچه در edو مشتقات آن ميباشند .با اين همه ،دو نوعت تنمونه،ت تبهت تمعناي تدوت تمجموعه تقوانينت تبراي تيادگيري توت تدوت تبخش تشامل تكدت تجهت پردازش تآنهات تميباشد .برخي تازت تتفاوتها،گزینه تهای تبعدی تمی تباشند تکه تهرگز تاصلح نشدند ،برای مثال هيچ دليلی غير از سازگاری برای این که برای تطبيق هر کاراکتر ed ،از نقطه استفاده ميكند و پوسته از ? ،نيست .اما گاهي نمونهها ،كارهاي متفاوتي انجام ميدهند تعبارات تبات تقاعده تدر تويرايشگر ،تبهت تدنبال ترشتهاي تميگردند تكه تممكن تاست هرجاي خط واقع شود؛ كاركترهاي ويژه ^ و ،$جهت اتصال جستجو به ابتدا و انتهاي خط ميباشند .به هرحال ،براي نام فايلها ،بايد جستجو را به صورت پيش فرض ،تثبيت كنيم، چرا كه بسيار پيش ميآيد كه مجبور باشيم بنويسيم: ∧?*. C$
1S
$
محیط برنامه سازی لینوکس
130/322
به جاي $
1S *.C که بسیار ايجاد مزاحمت ميکند.
تمرين . ۵-۱اگر كاربران نسخة calشما را ترجيح دهند ،براي استفادة جهاني از آن چه تدبيري ميانديشيد؟ براي گذاشتن آن در usr/bin/چه بايد كرد؟ تمرين . ۵-۲آيا تنظيم calبه گونهاي كه cal ۸۳تقويم ۱۹۸۳ترا چاپ كند ،ارزشمند مي باشد؟ اگر چنين است ،تقويم ۱۹۸۳را چگونه چاپ ميكنيد؟ تمرين cal . ۵-۳را بگونهای تعريف کنید که بیتشر از يك ماه را قبول کند ،همانند: يا درصورت امکان تعدادی از ماهها را:
$ cal oct nou $ cal oct – dec
اگر اكنون دسامبر باشد و شمات cal janرا بخواهيد ،ژانوية سال جاري را خواهيد ديد يا سال آينده را؟ چه زماني بايد اضافه كردن ويژگيها را به calمتوقف كنيد . which .۲۵كدام دستور است؟ در ساختن نسخههای خصوصي از دستورهايي مانند ، calمشکلتي وجود دارد .واضحترين مشکل ،اين است که اگر با Maryکار
ميکنید و در حالي calرا تايپ کنید که با عنوان maryوارد سیستم شده باشیدcal،استاندارد را به جای نمونة جديد خواهید ديد،
البتهمگر اينکه Mary calجديد را با دايرکتوری binخود مرتبط ساخته باشد .اين امر ميتواند گمراه کننده باشد ـ به خاطر بیاوريد که پیغامهای خطا ازـ calاصلي ،چندان مفید نميباشند ـ اما تنها ميتواند مثالي از يك مسئله کلي باشد .از آنجايي که پوسته در يك مجموعه از دايرکتوريها که بوسیلة PATHمشخص شدهاند ،به دنبال دستورات ميگردد ،همیشه امکان اين وجود دارد که به نسخهای از
يك دستور ،غیراز آنچه انتظار داريد ،برخورد کنید .برای مثال ،اگر دستوری را تايپ کنید ،فرضا ، echoنام مسیر فايلي که واقعا ً اجرا ميشود ،ميتواند
usr/bin/echo/0 ،
/ bin/echoيا چیز ديگری باشد ،که بستگي به اجزاء PATHو محل قرارگیری فايلها
دارد .وقوع يك فايل اجرايي با نام صحیح اما رفتار اشتباه غیر از آنچه انتظار داريد در جستجو ،ميتواند گمراه کننده باشد .احتمالً
معمول ترين نمونه ،دستور testميباشد که بعدا ً به آن خواهیم پرداخت :نام آن برای يك نسخة موقت برنامه ،چنان واضح است که
برنامة testاشتباه ،ميتواند بطور آزار دهندهای فراخواني شود .دستوری که گزارش دهد کدام نسخه برنامه اجرا خواهد شد ،بسیار مفید و مورد استفاده خواهد بود.
يك شیوة اجرا ،حلقه زدن زياد دايرکتوری هايیست که در PATHنام برده شده و جستجوی هرکدام برای يك فايل قابل اجرا است که
نام آن موجود ميباشد .درفصل ، ۳از FORبرای حلقه زدن نام فايلها و آرگومانها استفاده کرديم .در اينجا ،به حلقهای نیاز داريم که بگويد:
For iدر هر جز از PATH اگر نام ارائه شده در دايرکتوری i ،موجود است.
do
محیط برنامه سازی لینوکس
131/322
نام کامل سیر آن را چاپ کن
done از آنجا که ميتوانیم هر دستوری را درون '…' اجرا کنیم ،راه حل واضح ،اجرا کردن ،sedپیش از $ PATHاست و تبديل در نقطه فاصله .ميتوانیم اين موضوع را با دوست قديمیان echoامتحان کنیم.
جزء ۴ !تنها ۳چاپ شده
$ echo $ PATH : usr/you/bin : .bin : / usr/bin ''s/ : / /g
` ' 's/ : / g هنوز فقط 3
$ echo $ PATH | sed /usr / you / bin / bin / usr / bin $ echo `echo $ PATH | sed /usr / you / bin / bin / usr / bin $
به وضوح يك مسئله وجود دارد .يك رشتة خنثي در ،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ميباشند و بايد برای هر نوع تطبیق نمونهای مورد استفاده قرار گیرند:
"$/" in hello ( command esac Will be faster than
Case
محیط برنامه سازی لینوکس
133/322
if tset '' $1'' = hello کندتر مگر آنکه testدستوری دروني در پوسته باشد
then
command fi
يك دلیل برای اينکه گاهي از جملت ،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حلقه ايجاد ميکند .آنرا قابل اجرا ميکند.
آنرا قابل اجرا مي کند Which Which $ مردود مي شود !
$ echo 'echo hello′ >test $ cx test را امتحان مي کند 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جعلي نیز در خلل جستجو وجود داشته باشد ،عمل مي کند.
still there
$ 1S – 1 test rwxrwxrwx 1 you 11 oct 1 06:55 test $ 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
echo file filename dose not exist
then fi
عملگر ¦¦ ،علي رقم ظاهر آن ،هیچ ربطي به لولهها ندارد ـ عملگری است شرطي به معنای . OR
دستور سمت چپ ¦¦ به اجرا درخواهد آمد .اگر وضعیت خروج آن ،صفر باشد( ،موفقیت) ،دستور سمت راست ¦¦ ناديده گرفته ميشود.
اگر سمت چپ ،مقداری غیر صفر را برگرداند (عیب) سمت راست اجرا شده و مقدار کل عبارت ،وضعیت خروج سمت راستي خواهد بود .به عبارت ديگر ¦¦ ،يك عملگر ORشرطي است که دستور سمت راست خود را در صورت موفقیت سمت چپ ،اجرا نميکند.
&& شرطي پاسخ AND ،ميباشد؛ دستور سمت راست خود را خود را تنها هنگامي اجرا ميکند که سمت چپي موفقیت آمیز باشد.
تمرين . ۵-۴چرا PATH Whichرا به ،Opathقبل از خروج مقدار دهي اولیه نميکند؟
تمرين . ۵-۵از آنجائیکه پوسته از esacبرای پايان دادن به يك caseاستفاده ميکندو از fiبرای اتمام يك ، ifچرا از doneبرای اتمام
doاستفاده ميکند؟
تمرين . ۵-۶يك گزينه aـ را به whichاضافه کنید.بگونهای که تمامي فايلها را در PATHچاپ کند به جای اينکه بعد از اولین فايل، خارج شود .راهنماييmatch=´exit O´ . :
تمرين Which . ۵-۷را بگونهای تعريف کنید که فرامین درون پوسته مانند exitرا بشناسد.
تمرين Which. ۵-۸را بگونه ای تعريف کنید که مجاز بودن اجرا را روی فايلها بررسي کند .آنرا جهت چاپ يك پیغام خطا هنگام نیافتن يك فايل ،تغییر دهید.
محیط برنامه سازی لینوکس
136/322
۵۳حلقههاي whileو : Loopمراقبت از اشياء در فصل سوم ،از حلقه 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 ثانيه صبر كنيد تا متوجه شويد. همچنين اگر maryدر اين حال بماند ،هر يك دقيقه يكبار از وضعيت آن ،مطلع خواهيد شد.
محتويات حلقه را ميتوان بيرون آورده و با 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
PATH = / bin : / usr / bin new = / tmp / wwho 1 . $$ old = / tmp / wwho 2 . $$ > $ old # create an ampty file while : # lopp forever do who > $ new diff $old $new mv $new $old sleep 60 done | awk ' / >/ } $1 = ''in : { '' ; print / < / } $1 = ''out : ' { '' ; print $ " ":يك دستور درون پوسته است که کاری به جز نشان دادن برهانهای خود و برگرداندنـ " درست" انجام نميدهد .در عوض،
ميتوانستیم از دستور 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
''`y = '' ` 1s -1 $ MSIL echo $ x $ y ''x = ''$y sleep $t '{ '' done | awk ' $4 < $1 } print ''you have mail $ دوباره از ، 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 $
کاراکترهای خاص درون براکتها ،پردازش ويژه متغیرها را مشخص ميکند .اگر متغیر تعريف نشده باشد و در پي نام آن علمت سؤال
آمده باشد ،رشتة بعد از ؟ چاپ ميشود و پوسته خارج ميشود (مگر اينکه تباد لي باشد) .اگر پیغام خاصي مهیا نشده باشد،استاندارد
آن بصورت زير چاپ ميشود:
O.K.;var is set پیغام پیش فرض پیغام اعمال شده
$ echo {? $ }var hello {?$ echo $ } junl junk : parameter not set { !$ echo $ } junk?error ! junk : error
توجه داشته باشید که پیغامي که توسط پوسته ساخته ميشود ،همواره شامل نام متغیر تعريف نشده است.
$
محیط برنامه سازی لینوکس
140/322
يك فرم ديگر $ }Var-thing { ،ميباشد که آنرا با $ Varارزيابي ميکند ،اگر تعريف شده باشد و با ، thingاگر تعريف شده نباشد.
{ $ }Var = thingنیز مشابه است ،اما thingرا نیز با $ Varمقدار دهي ميکند:
junkتأثیر نپذيرفته است
Hi , junkمقدار دهي شده
{ ' $ echo $ }junk- 'Hi there {?Hi echo $ }junk junk : parameter not set {' $ echo $ } junk= 'Hi there Hi there { ?$ echo $ } junk Hi there $
قوانین ارزيابي متغیرها ،در جدول ۵-۳آمده است.
بر ميگرديم به مثال ساده خودمانt = $ } 1-60 {،
tرا از روي ، $1يا اگر هيچ آلگومان اعمال نشده باشد ، جدول :۵-۳ارزيابي متغیرهای پوسته
60مقدار دهي ميکند. $ Var {$ } Var {$ } Var-thing
مقدار Var؛ اگر Varتعريف نشده باشد ،هیچ مقداری
مشابه است؛ اگر بعد از متغیر نام ،حروف و ارقام آورده شود.
اگر تعريف شده باشد ،مقدار Varو در غیر اين صورت thing $ Var ،تغییر {$ } Var = thing نمييابد.
اگر تعريف شده باشد ،مقدار Varو در غیر اين صورت $ Var ،
thingنمييابد.
thingمقدار {$}var?message
اگر تعريف شده باشد . $ Var ،در غیر اين صورت message ،را چاپ کرده و از
$ }Var+thing{$
پوسته خارج ميشود .اگر 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و کارکتر #درپوسته وجود دارد؟ آيا هر دو مورد نیاز هستند؟
Trap .22126 ۵۴ها ،وقفههاي جاذب اگرـ DELرا فشار دهید يا هنگام اجرایـ ، watchwhoگوشي تلفن را بگذاريد ،يك يا دو فايل موقت ،درـ / tmpباقي ميماند.
Watchwhoبايد آنها را قبل از خروج حذف کند و بايد راهي برای رويايي چنین حالتي و بازيافت آنها ،بیابیم.
هنگامي که DELرا تايپ ميکنید ،يك سیگنال وقفه به تمام پردازشهای در حال اجرا در ترمینال ،ارسال ميشود .مشابهاً ،هنگامي که گوشي را ميگذاريد يك سیگنال hang upفرستاده ميشود .سیگنالهای ديگری نیز وجود دارند .اگر برنامهای ،عملي واضح را در مورد
سیگنالها به کار نبندد ،سیگنال آنرا به اتمام ميرساند .پوسته برنامههايي که با & اجرا مي شوند را از وقفهها محافظت ميکند اما از تعلیق نه.
فصل هفتم سیگنالها را مفصل به بحث ميگذارد ،اما نیازی به شناختن زياد آنها برای به کار بستنشان در پوسته نیست. فرمان دروني پوسته ، Trapرشتهای از دستورها را هنگامي که سیگنال واقع ميشود ،جهت اجرا ميچیند:
فهرستي از شمارههای سیگنال
رشتهای از دستورات trap
رشتهاي از دستورات ،آرگوماني منفرد است ،از اين رو بايد تقريباً هميشه داخل كوتيشن قرار گيرد. شمارههاي سيگنال ،ارقام كوچكی هستند كه سيگنال را معرفي ميكنند .براي مثال ۲ ،سيگنالي است كه بواسطة فشردن كليد DELبوجود ميآيد .و ۱بواسطة گذاشتن گوشي ،بيشتر شمارههاي سيگنال مفيد براي برنامهنويسان پوسته در جدول ۵-۴آمدهاند.
جدول ۵-۴شمارههای سیگنال پوسته خروج از پوسته (به هر دلیلي ،از جمله پايان فايل)
معلق شدن
وقفه (کلید ) DEL
0 1 2 3 9 19
خروج ( Ctl-1باعث ميشود برنامه انباری موقتي در هسته ايجاد کند)
ازبین بردن (قابل صرف نظر پا گرفتن نیست)
اتمام ،پیغام پیش فرضي که توسط ( Kill )1ايجاد ميشود.
از اين رو جهت پاك کردن فايلهای موقتي در ،watchwhoيك فراخواني trapبايد دقیقا ً پیش از حلقه انجام گیرد ،تا تعلیق ،وقفه و اتمام را به دست گرفت:
... trap ' rm -f $new $ old ; exit 1' 1 2 15 while :
محیط برنامه سازی لینوکس
142/322
... رشته دستوری که اولین آرگومان را برای 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پیدا کند .اگر مشتاق هستید ( واجازه داريد) ،آنرا به دستوری اعمال کنید که کاربری جديد را به سیستم اضافه کند .چه مجوزهايي نیاز دارد؟ چگونه بايد با وقفهها برخورد
کند؟
.۵۵جايگزين كردن يك فايل Over write
دستور ، commandداراي يك گزينة - 0است جهت بازنويسي يك فايل sort file1 – 0 file2 $ معادل است با
sort file > file2 $ اگر file1و file2معادل باشند ،دوباره جهت دهي بوسیلة > ،فايل ورودی را قبل از مرتب کردن ،ناقص ميکند .اما گزينه ، - 0درست کار مي کند ،چرا که ورودی در يك فايل موقت ،مرتب و ذخیره شده است ،پیش از اينکه فايل خروجي بوجود آيد.
بسیاری دستورات ديگر قادر به استفاده از گزينه - 0مي باشند .برای مثال sed ،ميتواند فايلي را درجای خود ويرايش کند: عمل نمي کند !
$ sed 'S/UNIX/UNIX(TM)/g' Ch2-O Ch2
تعريف چنین دستورهايي جهت افزودن گزينه ،غیر عملي خواهد بود .علوه بر اينکه ،طرحي بد خواهد بود :بهتر است که توابع را هم مرکز کنیم ،همانگونه که پوسته با عملگر > انجام ميدهد .برای اين کار 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
cat > $new # collect the input cp $ new $1 # overwrite the input file rm -f $ new ، Cpبه جای mVاستفاده ميشود تا مجوزها و مالكهای فايل خروجي ،در صورت وجود آن ،تغییر نکنند .همانگونه که به سادگي از اين نسخه بر ميآيد ،دارای يك نقص مضر است :اگر کاربر DELرا در حین CPتايپ کند ،فايل ورودی اصلي ،ازبین خواهد رفت. بايد از وقوع وقفه حاصل از متوقف ساختن بازنويسي فايل ورودی ،جلوگیری کنیم:
# overwrite : copy standard input to output sfdter EOF # version 2. BUG here too PATH=/bin : /usr/bin case $# in (1 ;; ( • echo `Usage : overwrite file ' 1>&2; exit 2 esac new= /tmp/overwr 1.$$ old=/tmp/overwr2 .$$ trap 'rm -f $new $old; exit 1' 1 2 15 cat >$new #collect the input cp $1 $old # save original file trap ' ' 1 2 15 # we are committed; ignore signals cp $new $1 # overwrite the input file rm -f $new $old
اگر پیش از دستیابي به فايل اصلي ،يك 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 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 $ overwrit notice sed 's /UNIX/UNIX)TM(/g' notice $ cat notice UNIX )TM( is a Trademark of Bell Laboratorise $
. غیر قابل دسترس مي بودندOverwrite برای
اکنون عمل مي کند
Unehanged
محیط برنامه سازی لینوکس
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ببینید .راه حل شما ،چگونه بر تفسیر متاکاراکترها در دستور تأثیر ميگذارد.
: Zap .۵.۶از بين بردن فرآيند ،از روي نام دستور 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
چه اتفاقي مي افتد؟
0? q
مسأله اين است که خروجي 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جاهاي خالي آرگومانها ما تقريبا ً با هر آنچه برای نوشتن دستور pickدر پوسته نیاز داريم،بر خورد داشتهايم .تنها چیز جديدی که نیاز است ،مکانیزمي است برای خواندن ورودی کاربر .دستور داخلي پوسته ، readيك خط از متن را از ورودی استاندارد خوانده و متن را به عنوان مقدار متغیر
نام برده مي خواند (بدون خط جديد).
$ read greeting . hello , worldوارد کنید greetingمقداری جديد برای
$ echo $ greeting hello , world $ معمولترين استفاده readدر .profileاست جهت تنظیم محیط ،هنگام ورود به سیستم تا متغیرهای پوسته مقدار دهي اولیه شوند ،مانند
.TERM Readفقط ميتواند از ورودی استاندارد بخواند؛ حتي قابل جهت دهي مجدد نیز نیست .هیچ يك از دستورات درون پوسته (برخلف اصول اولیه کنترل جريان مانند ) forقابل جهت دهي مجدد با > يا < نیستند.
$ read greeting </etc/passwd
محیط برنامه سازی لینوکس
150/322
بايد مقداری وارد شود
اکنون پوسته گزارش خطا ميدهد
مقداری را وارد کرده ،نه از فايل Greeting
goodbye illegal io $ echo $greeting goodbye $
اين امر را ميتوان به عنوان نقصي در پوسته قلمداد کرد ،اما واقعیت دارد .خوشبختانه مي توان با دوباره جهت دادن حلقه محاط بر 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 :آرگومانها را درست جابجا ميکند .ميتوانستیم حلقه را به روشهای
ديگری بنويسیم:
see what this version does
$ grep for pick * 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آرگوماني نداشته باشد ،بايد ورودی استاندارد خود را بخواند ،از اين رو ميتوان از:
> < mailing list
$ Pick به جای
` $ 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
جايگزين کردن دستور محلي شما نیست بلکه برای اينست که نشان دهیم به چه سادگي چنین برنامهای را در پوسته ،ميتوان نوشت.
مقايسة دستور 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 $
بايد IFSرا از خط جديد مقدار دهي کنیم تا پیغام به سه کلمه تجزيه نشود.
./.news-time no found
محیط برنامه سازی لینوکس
154/322
در قدم بعدی news ،بايد فايلهای خبری را چاپ کند ،به جای آنکه نام آنها را برگرداند .اين کار از اين بابت مفید است که ميتوان
فهمید چه کسي و چه زماني را ارسال نموده ،و از اين رو از دستور setو LS-1برای چاپ يك سرصفحه قبل از خود پیغام ،استفاده ميکنیم:
news
208 o ct 1 12:05
اشتباهي رخ داده است !
$ 1s -1 news – r wxrwxrwx 1 you ` $ set `1s -1 news (- rwxrwxrwx: bad optin)S –
$
اينجا،ت تمثالي تاست تازت تجايي تكهت تقابليت تجابجايي تبرنامهها توت تدادههات تدرت تپوسته،ت تمورد استفاده قرار ميگيرد.
Setاعتراض ميكند ،چرا كه آرگومان آن (" )"rwnrwxrwx-باعلمت منفي شروع شده و مانند يك گزينه ببه نظر ميآيد .يك راه حل ساده (اگر باهوش باشيد) ،افزودن يك پيش وند است به آرگومان مانند يك كاركتر عادي: ` $ set X ` 1s -1 news '' $ echo ''news: )$3( $5 $6 $7 news: )you( oct 1 12:05 $ اين يك غالب قابل قبول است و نويسنده و تاريخ پیغام را همراه با نام فايل نشان ميدهد. در اينجا آخرين ويرايش دستور 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در دستورات مشابه روی سیستم خود را با يکديگر مقايسه کنید.
get .۵۹و : putرديابي تغييرات فايل در اين بخش ،تا آخرين بخش يك فصل طولني ،يك مثال بزرگتر و پیچیدهتر را به بحث ميگذاريم که همکاری پوسته را با sed ,
، awkتشريح ميکند.
يك برنامه ،با درست کردن معايب و اضافه کردن ويژگیها ،تکامل مييابد .گاهي رديابي اين ويرايشها ،به ويژه هنگامي که افراد برنامه را
برای ساير ماشینها به کار ميبرند ،ساده مينمايد ـ برميگردند سئوال ميکنند « از وقتي که ويرايش ما نصب شده ،چه تغییری حاصل
شده؟ » يا « اين عیب يا آن مشکل را چگونه برطرف کرديد؟ » همچنین ،همواره نگهداشتن نسخههای پشتیبان ،تجربه کردن ايدهها را بيآسیب تر ميکند :اگر چیزی کار نميکند ،بازگشتن به برنامه اصلي ،بدون دردسر خواهد بود .يك راه حل ،نگه داشتن کپيهای تمام
ويرايشهاست ،اما اين کار با زحمت و هزينة زيادی همراه است .درعوض ،بر روی نسخههايي متمرکز ميشويم که دارای بسیاری
قسمتهای مشترك بوده و يکبار نیاز به ذخیره شدن دارند.
دستور
diff - e old new
$
فهرستي از دستورات edرا که oldرا به newتبديل ميکنند ،ايجاد ميکند ،از اين رو نگهداشتن تمامي نسخههای يك فايل در يك فايل جداگانه (متفاوت) با نگهداری يك نسخة کامل و مجموعهای از دستورات ويرايشي برای تبديل آن به هر نسخه ،میسر ميشود.
دو نوع سازماندهي وجود دارد :جديدترين ويرايش را در دسترس نگه داشته و دستورات ويرايشي را عقب برد و يا قديميترين
ويرايش ها را نگه داشت و دستورات ويرايشي را جلو برد .باوجود اينکه دومي برای برنامه نويسي سادهتر است ،اولي سريعتر است اگر
ويرايشهای زيادی در دسترس باشد .ما سازماندهي اول را انتخاب ميکنیم .در يك فايل منفرد که آنرا فايل تاريخچه نام گذاری ميکنیم، ويرايش جاری و در پي آن مجموعهای از دستورات ويرايشي که هر ويرايشي را به ويرايش قبلي برميگرداند ،موجود مي باشند.
هرمجموعه از دستورات ويرايشي ،با خطي شروع ميشوند مشابه
خلصه
تاريخ
شخص
@@@
خلصه ،خطي است منفرد ،که بوسیله شخص تأمین شده و تغییر را توصیف مينمايد .برای نگهداری از نسخهها ،دو دستور وجود
دارد get :ويرايشي را از فايل تاريخچه گرفته و putنسخهای جديد را به آن وارد مينمايد ،پس از اينکه يك خط خلصة تغییرات
درخواست شود.
پیش از نشان دادن کاربرد ،مثالي در اينجا برای بیان چگونگي عمل getو putو فايل تاريخچه چگونه نگهداری ميشود ،آورده شده:
محیط برنامه سازی لینوکس
156/322
$ echo a line of text >junk $ put junk Summary: make a new file get: no file junk . H put: creating junk . H
توصیفات را وارد نمايید
..... تاريخچه موجود نميباشد آنرا ايجاد ميکندput ......
$ cat junk . H a line of text @@@ you sat oct 1 13:31:03 EDT 1983 make a new file $ echo another line >> junk $ put junk summary: one line added $ line of text 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 $ . ويرايش جديد را به نسخة اصلي برميگرداند، که خط دوم فايل را از بین ميبرند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
. کپي ميشودoverwrite با استفاده از،فايل
. است که بیشتر به خاطر داشتن گزينههاستput پیچیدهتر ازget
# get: extract file from history PATH=/bin:/usr/bin VERSION=0 while test ''$1'' ! = '' '' do case ''$1'' in -i ( INPUT=$2; shift ;; -o ( OUTPUT=$2; shift ;; -]0-9[ ( VERSION = $1 ;; – * ( echo ''get: Unknown srgument $i'' 1>&2; exit 1 ;; • ( case ''$OUTPUT'' in '' '' ( OUTPUT = $1 ;; • ( INPUT = $1.H ;; esac esac shift done OUTPUT= $ }OUTPUT? ''Usage: get ]- o outfile[ ]-i file . H[ file ''{ INPUT = $ } INPUT - $OUTPUT.H { test -r $ INPUT | | } echo ''get: no file $ INPUT'' 1>&2; exit 1; { trap 'rm -f /tmp/get.]ab[ $$; exit 1' 1 2 15 # split into current version and editing commands sed < $ INPUT -n ' 1 ,/^@@@/w /tmp/get.a'$$' /^@@@/ ,$w /tmp/get.b'$$ # perform the edits awk </tmp/get.b$$ ' /^@@@/ } count ++ { !/^@@@/ && count > 0 && count < = '$VERSION' END } print ''$d''; print ''w'' , '' ' $OUTPUT ' '' { ' | ed - /tmp/get.a$$ rm -f /tmp/get.]ab[ $$ ويرايشي خاص را انتخاب، - ]0-9[ . ورودی و خروجي را مشخص ميکنند، - O – وi . کامل ً عادی و معمولي ميباشند،گزينهها است با يكwhile ، يکي مانده به جديدترين و … حلقة شامل آرگومانها-1 ، ) جديدترين ويرايش است (پیش فرضO :مينمايد داد وshift ) از يك آرگومان ديگر نیز استفاده کرده و بايد آنرا- i – وO( چرا که برخي گزينهها، ميباشدfor به جایshift وtest
شمارش کارکتر را که، ed » - « گزينة. با هم به درستي کار نميکنند، باشدfor داخل حلقهshift اگر،هاshift وfor اينکه حلقههای
.معمولً به همراه خواندن يا نوشتن يك فايل اجرا ميشود را متوقف ميکند
خط test -r $INPUT | | } echo '' get: no file $INPUT'' 1>&2; exit 1; { معادل است با:
محیط برنامه سازی لینوکس
159/322
if test ! -r $INPUT then echo ''get: no file $ INPUT'' 1>&2 exit 1 fi (که همان فرمي است که برای putاستفاده نموديم) اما کوتاهتر و برای برنامهنويساني که با عملگر ـ | | آشنا هستند ،واضحترا ست. دستورهای بین { ، },در پوستة جاری اجرا ميشوند ،دريك زير پوسته؛ اين امر الزامي است چرا که exitاز getخارج مي شود و نه
فقط از يك زيرپوسته .کارکترهای { },مانند doو doneميباشند ـ اگر بعد از آنها ،يك « ; » يا خط جديد يا هر پايان دهندة دستور، دارای معني خاصي است.
سرانجام سراغ کد واقع در getکه اين کار را انجام ميدهد ميآيیم .درابتدا sed ،فايل تاريخچه را به دو قسمت تقسیم ميکند :آخرين
نسخه و مجموعة ويرايشها .سپس برنامة ،awkفرامین ويرايشي را پردازش ميکند .خطوط @@@ ،شمرده (و نه چاپ) ميشوند و آنجايي که شمارش ،بیشتر از ويرايش موردنظر نباشد ،دستورهای ويرايشي ،عبور ميکنند (به خاطر بیاوريد که عملکرد پیش فرض
،awkچاپ کردن خط ورودی است) .دو دستور edپس از آن از فايل تاريخچة اضافه ميشوند ، $d :خط @@@ را ، sedآنرا در
ويرايش جديد ،رها ميکند ،حذف مينمايد ويك دستورـ ، Wفايل را در موقعیت نهايي خود ،مينويسد Overwrite .در اينجا
غیرالزامي مينمايد ،چرا که getتنها ويرايش فايل را تغییر ميدهد و نه فايل ارزشمند تاريخچه را.
تمرين . ۵-۲۹يك versionدستوری بنويسید که دو کار انجام دهد:
version -5 file $ خلصه ،تاريخ تغییر و شخصي که تغییر ويرايش انتخاب شده را در فايل تاريخچه انجام دهد: version sep 20 file $
گزارش دهد که کدام شماره ويرايش در ۲۰سپتامبر جاری بوده،که نوعا در
`get `version sep 20 file $
مورد استفاده قرارميگیرد 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 اين بخش شامل مقدمه مختصر زبان cمي باشد .قصد داشته به عنوان خود آموز زبان بوده ،و با اين هدف که خواننده ای که cرا تازه
شروع کرده به سرعت ممکن برسد .مطمئنا بعنوان جانشیني برای کتابهای درسي بیشمار cنیست.
بهترين راه آموزش يك زبان جديد انساني صحبت کردن آن درست از آغاز است .گوش دادن و تکرار پیچیدگي های دستور زبان را از
بین مي برد .همینطور برای زبان های کامپیوتری -يادگیری -cبکار مي رود و ما بايد نوشتن برنامه های cرا با سرعت ممکن آغاز
کنیم.
يك کتاب درسي عالي 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شامل اصلحیه های زياد نحوی و کارهای
دروني زبان مي باشد .موارد مهم اصلح شده نحو فراخواني برای روالها و استاندارد سازی بیشتر کتابخانه های سیستم است ( ولي،
متاسفانه نه تمام آنها)
یک برنامه مقدماتی با نام خدا شروع مي کنیم
برنامه زير را در ويرايشگر مورد علقه خود تايپ کنید.
کد را در فايل hello.cذخیره ،و سپس با تايپ gcc hello.cآن را ترجمه (کامپايل) کنید.
اين يك فايل قابل اجرای a.outرا بعد از اجرا بسادگي با تايپ نام آن ايجاد مي کند.
># include <stdio .h ( ) void main } ;(”print f )“\ nHello world \n {
در نتیجه کاراکترهای Hello worldبا يك خط خالي چاپ مي شود.يك برنامه cشامل توابع و متغیر هاست .توابع کارهايي که توسط برنامه اجرا مي شوند را مشخص مي کنند.
محیط برنامه سازی لینوکس
162/322
تابع «( »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 {
سعي کنید " ”\nرا خارج کرده و نتیجه را ببینید.
اولین حکم "> ”#include<stdio.hشامل مشخصه کتابخانه I/Oزبان cاست .همه متغیرهای cبايد صريحا قبل از استفاده تعريف
شوند .فايل های " ”hفايل های سر آيند بوده که شامل تعريف متغیرها و توابع لزم برای کار کردن برنامه ها چه در بخش نوشته شده توسط کاربر از کدباشند ،يا بعنوان کتابخانه های استاندارد cباشد ،مي باشد .نماد "> ”<....مترجم را برای جستجوی فايل در کتابخانه های استاندارد سیستم راهنمايي مي کند.
کلمه voidقبل از mainمشخص مي کند که تابع mainاز نوع voidاست .يعني هیچ نوع وابسته به آن ندارد .به اين معنا که نمي
تواند نتیجه ای را هنگام اجرا برگرداند.
کاراکترـ ";” انتهای دستور را مشخص مي کند .بلوکهای دستورات در آکولدـ { }....قرار مي گیرند ،همانند تعريف توابع .تمام دستورات cدر فرمت آزاد تعريف مي شوند .بدون طرح بندی مشخص شده يا انتساب ستون .فضای سفید ( تبها يا فاصله ها) معني
ندارند .بجز درون کوتیشن ها ( نقل قول) بعنوان بخشي از رشته کاراکتری .برنامه زير دقیقا همین نتیجه را برای مثال ما مي دهد:
دليل مرتب کردن برنامه در خطوط و نمايش ساختار واضح است.
>#include < stdio.h {;("void main)(}printf)"\nHello World\n
محیط برنامه سازی لینوکس
163/322
محاسبه . درجه محاسبه مي کند۳۶۰ تا۰ را برای زاويه های بینsine جدولي از توابعsine.c ،برنامه زير
/************************/ /* Table of */ /* Sine Function */ /************************/ /* Michel Vallieres */ /* Written: Winter 1995 */ #include < stdio.h> #include < math.h> void main)( } int angle_degree; double angle_radian, pi, value; /* Print a header */ printf )"\nCompute a table of the sine function\n\n"(; /* obtain pi once for all */ /* or just use pi = M_PI, where M_PI is defined in math.h*/
pi = 4.0*atan)1.0(; printf ) " Value of PI = %f \n\n", pi (; printf ) " angle angle_degree=0;
Sine \n" (; /* initial angle value /* scan over angle */
*/
while ) angle_degree <= 360 ( /* loop until angle_degree > 360 */ } angle_radian = pi * angle_degree/180.0 ; value = sin)angle_radian(; printf ) " %3d %f \n ", angle_degree, value (;
{
{
angle_degree = angle_degree + 10; /* increment the loop index
*/
محیط برنامه سازی لینوکس
164/322
کد با توضیحاتي ك هدف آن را مشخص مي کند شروع مي شود.
اين يك سبك خوب برنامه نويسي است که کار شما را مشخص و مستند مي کند.
توضیحات مي توانند هر جايي از کد نوشته شوند:هر کاراکتر بین *\ *\ ,توسط مترجم ناديده گرفته مي شود و فقط برای کد استفاده مي شود .استفاده از نامهای متغیر با معني در متن مساله نیز نظر خوبي است.
دستور # includeاکنون شامل فايل سر آيند برای کتابخانه رياضي استاندارد math.hمي باشد .اين دستور نیاز به تعريف فراخواني
های توابع مثلثاتي atsnو sinدارد( .توجه کنید که compilationهمچنین بايد شامل کتابخانه رياضیات دقیقا با تايپ gcc sine.c
-lmباشد).
نام های متغیر دلخواه است ( .توسط بعضي از مترجم ها طول ماکزيمم نوعا ۳.۲کاراکتر تعريف شده )
cاز انواع متغیرهای استاندارد زير استفاده مي کند.
: intمتغیر صحیح
: shortصحیح کوتاه
:longصحیح طولني
:floatمتغیر حقیقي
: doubleمتغیر حقیقي ( متغیر شناور ) دقت مضاعف
:charمتغیر کاراکتری (يك بايت )
مترجم ها سازگاری انواع همه متغیرهای استفاده شده در کد را بررسي مي کنند .اين ويژگیها باعث جلوگیری از اشتباه مي شود .و خصوصا در خطای نوع نام های متغیر .محاسبات انجام شده در روالها در کتابخانه رياضي معمول در دقت مضاعف محاسبه شده ۶۴ ( . بیت در بیشتر ايستگاههای کاری ) تعداد واقعي بايتها در حافظه دروني اين انواع داده وابسته به ماشیني که استفاده شده بکار رفته است.
تابع ، printfمي تواند برای چاپ مقادير صحیح ،حقیقي و رشته ها بکار رود نحو کلي اين است:
; (printf)“format” ,variable که formatمشخصه تبديل و variableفهرست مقادير چاپ است .بعضي فرمتهای مورد استفاده عبارتند از؛
:%ndصحیح ( nاختیاری = تعداد ستونها ؛ اگر 0باشد ،با صفر پر مي شود )
: %mnfمتغیر حقیقي ساده يا مضاعف ( mاختیاری = تعداد ستونها و nتعداد ارقام اعشار )
: %nsرشته ( nاختیاری = تعداد ستونها )
:%cکاراکتر
\ : n\tبرای ايجاد خط يا تب جديد
: \gصدای زنگ ( “ بیپ" ) بر روی پايانه ( ترمینال)
محیط برنامه سازی لینوکس
165/322
۳حلقه ها: اکثر برنامه های واقعي شامل ساختاری است که در برنامه حلقه مي زند .اجرای عملهای مکرر در يك جريان داده يا ناحیه ای از حافظه. چندين روش برای حلقه در cوجود دارد .دو حلقه بسیار رايج يکي whileاست. ( whileعبارت )
{ ...............بلوك دستورات برای اجرا ...... } و ديگر حلقه for
( forعبارت ۳؛ عبارت ۲؛ عبارت )۱ { ........بلوك دستورات برای اجرا ....... }
حلقه whileبه حلقه ادامه مي دهد تا زمانیکه عبارت شرطي نادرست شود .شرط هنگام ورود به حلقه تست مي شود .هر ساختار منطقي ( فهرست زير را ببینید) مي تواند در اين زمینه استفاده شود.
حلقه forيك نوع خاص است و معادل است با حلقه 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
و مشتقات متفاوت آن .هم با حذف شاخه ها يا شامل شرايط تو در تو.
شرط ها عملگرهای منطقي شامل مقايسه مقادير ( از يك نوع ) هستند که از عملوندهای شرطي استفاده مي کنند.
< کوچکتر از
= < کوچکتر از يا مساوی با = = مساوی با
= ! مساوی نیست با
= > بزرگتر از يا مساوی با > بزرگتر از
و عملوند های بولي && | | not
و
يا
نه
کاربرد ديگر شرط در ساختار switchاست.
(switchعبارت ) {
case
عبارت ثابت ; ۱
{ ..........بلوك دستورات ......... ; break } عبارت ثابت ; ۲ case
{ .........بلوك دستورات ........
; break } : default { ..........بلوك دستورات ......... } }
بلوك مناسب دستورات مطابق مقدار عبارت ،مقايسه شده توسط عبارت های ثابت در دستور caseاجرامي شود .دستور breakاطمینان
مي دهد که caseهايي ك در ادامه caseانتخاب شده آمده اند اجرا نخواهند شد.
اگر شما مي خواهید اين دستورات را اجرا کنید .بايد دستور breakرا رها کنید .اين ساختار بويژه در بررسي متغیر ها ورودی کاربرد دارد.
محیط برنامه سازی لینوکس
168/322
اشاره گرها زبان cبه برنامه نويس اجازه خواندن و نوشتن در محلهای حافظه را بطور مستقیم مي دهد .اين قابلیت انعطاف بال وقدرت زبان رانشان مي دهد .البته يکي از موانع بزرگي است که برنامه نويس مبتدی بايد دراستفاده از زبان چیره شود.
همه متغیر های يك برنامه در حافظه مقیم هستند .دستورات ; float X x = 6.5
نیاز دارد که مترجم ۴بايت از حافظه را در يك کامپیوتر ۳۲بیتي برای متغیرهای ممیز شناور xذخیره کند و سپس مقدار 6.5را درآن قرار دهد.
گاهي اوقات ما مي خواهیم بدانیم يك متغیر در کجاهای حافظه مقیم است .آدرس ( مکان در حافظه ) هر متغیر با قرار دادن عملوند
"&” قبل از نام آن بدست مي آيد .بنابراين & ampxآدرس xاست.
cبه ما امکان رفتن به مرحله بالتر و تعريف متغیر را مي دهد ،که اشاره گر نامیده مي شود .شامل آدرس ( يعني "( ) “ points to
اشاره به ) متغیر های ديگراست .برای مثال
pxرا به عنوان اشاره گر به اشیاء نوع شناور تعريف مي کند ،و آن را برابر با آدرس xقرار مي دهد
;float x ;float* px ;x = 6.5 ;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
;pc = )char*( px (( )*chartدر خط آخر يك " طرح“ است که يك نوع داده را به نوع ديگر تبديل مي کند ) px :و pcهر دو به يك مکان در حافظه اشاره مي کنند.يعني آدرس .xالبته px+1و pc+1به مکانهای متفاوتي از حافظه اشاره مي کنند.
به کد ساده زير توجه کنید:
/* x and y are of float type */ /* fp and fp2 are pointers to float */ */
/* x now contains the value 6.5
()void main } ;float x, y ;float *fp, *fp2 ;x = 6.5
/* print contents and address of x */ ;(printf)"Value of x is %f, address of x %ld\n", x, &x /* fp now points to location of x */ */
;fp = &x
/* print the contents of fp ;(printf)"Value in memory location fp is %f\n", *fp
/* change content of memory location */ ;*fp = 9.2 ;(printf)"New value of x is %f = %f \n", *fp, x /* perform arithmetic
*/
;*fp = *fp + 1.5 ;(printf)"Final value of x is %f = %f \n", *fp, x */
/* transfer values
;y = *fp ;fp2 = fp ;(printf)"Transfered value into y = %f and fp2 = %f \n", y, *fp2
{
اين کد را اجرا کنید و نتايج اين عملوند های مختلف را ببینید .دقت کنیدکه ،زمانیکه مقدار اشاره گر ( اگر شما آن را با printfچاپ کنید ) نوعا يك متغیر بزرگ است؛ مکان خاصي از حافظه در کامپیوتر ،را مشخص مي کند .اشاره گرها مقادير صحیح نیستند – آنها
يك نوع داده کامل متفاوت هستند.
۷آرايه ها: آرايه ها از هر نوع مي توانند در cشکل بگیرند .نحو آن ساده است:
[بعد] نام آرايه
محیط برنامه سازی لینوکس
170/322
در ،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
۸آرايه هاي كاراكتري يك ثابت رشته ای ،نظیر "”I am a string
يك آرايه از کاراکتر ها مي باشد .که به طور داخلي در cتوسط کاراکترهای اسکي ( )ASCIIدر رشته موجود است.
يعني " ، ”iفاصله و " ”aو " ”mو ........برای رشته بال ،وبا کاراکتر ويژه /0پايان يافته بنابراين برنامه مي توانند انتهای رشته را پیدا کنند.
ثابت های رشته ای اغلب در ايجاد خروجي کد قابل فهم با استفاده از printfبکار مي روند.
;("printf)"Hello, world\n ;(printf)"The value of a is: %f\n", a ثابت های رشته مي توانند با متغیرها در ارتباط باشند c .متغیر نوع charرا فراهم کرده .که مي تواند شامل يك کاراکتر باشد – ۱بايت
– در يك زمان .يك رشته کاراکتر در يك حافظه نوع کاراکتری ذخیره مي شود ،يك کاراکتر اسکي در مکان .هرگز فراموش نکنید که از آنجا که رشته ها بطور قرار دادی با کاراکتر پوچ“ ”\oخاتمه مي يابند ،ما نیاز به يك مکان ذخیره اضافه در آرايه داريم!
کدهای 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 ;(printf)"Original message: %s\n", message /* copy the message to text_1 */ /* the hard way */
;i=0 ( 'while ) )text_1]i[ = message]i[( != '\0 ;i++ ;(printf)"Text_1: %s\n", text_1
/* use explicit pointer arithmetic */
;ta=message ;tb=text_2
محیط برنامه سازی لینوکس
172/322
while ) ) *tb++ = *ta++ ( != '\0' ( ; printf)"Text_2: %s\n", text_2(; } 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 */ printf)"Length of line: %d\n", )int(strlen)line((; /* find occurence of substrings */ if ) )sub_text = strchr ) line, 'W' ( (!= NULL ( printf)"String starting with \"W\" ->%s\n", sub_text(; if ) ) sub_text = strchr ) line, 'w' ( (!= NULL ( printf)"String starting with \"w\" ->%s\n", sub_text(;
محیط برنامه سازی لینوکس
173/322
( if ) ) sub_text = strchr ) sub_text, 'u' ( (!= NULL ;(printf)"String starting with \"w\" ->%s\n", sub_text
} قابليت هاي ( ورودي /خروجي)I/o سطح کاراکتر I/o ( cاز طريق کتابخانه هايش ) روتین های گوناگون 1/0را فراهم کرده است .در سطح کاراکتر ( ) getcharکاراکتر را در يك زمان از stdinمي خواند .هنگامیکه ( ) putcharيك کاراکتر را در يك زمان روی stdoutمي نويسد .برای مثال ،توجه کنید:
include < stdio.h># ()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شما) مي نويسد .اين جريانات همیشه در زمان اجرا تعريف مي
شوند( EOF .پايان فايل) مقدار مشخصي را بر مي گرداند .که درـ stdiohتعريف شده وتوسطـ (
) getcharهنگامیکه در زمان
خواندن با نشانه end- of-fileمواجه شد ،بر گردانده مي شود .مقدار آن به کامپیوتر بستگي دارد .البته کامپايلر cاين واقعیت را از کاربر با تعريف متغیر EOFپنهان مي کند .بنابراين برنامه کاراکتر ها را از stdinخوانده و مجموع آن را در شمارنده ncنگه مي دارد .تا
زمانیکه با "( ”end of fileانتهای فايل) روبرو شود.
يك برنامه نويس با تجربه cاحتمال اين برنامه را به صورت زير کد مي کند :
<include < stdio.h# ()void main } ;int c, nc = 0
محیط برنامه سازی لینوکس
174/322
;while ) )c = getchar)(( != EOF ( nc++ ;(printf)"Number of characters in file = %d\n", nc cامکان عبارات مختصر زيادی را مي دهد .معمول با قابلیت خوانائي!
{
( ) در دستورات ( ( ) )c=getcharاجرای فراخواني ( ) getcharرا بیان مي کند .و نتیجه را cقبل از مقايسه آن با EOFانتساب مي کند( .قرار مي دهد)
کروشه ها اينجا لزم است .بیاد داشته باشید نماد گذاری ( nc++و در حقیقت ) ++nc ،راه ديگری برای نوشتن nc=nc+1است.
(تفاوت بین نمادگذاری پیشوند و پسوند است که در nc ، ++ncقبل از اينکه استفاده شود افزايش يافته.در حالیکه در nc ، nc++قبل از اينکه افزايش يابد استفاده مي شود.
در اين مثال خاص ،هر دو انجام شده ) اين نماد گذاری فشرده تر است و اغلب بطور مؤثرتری توسط مترجم کد مي شود.
فرمان wcيونیکس کاراکترها و کلمات و خطوط را در يك فايل مي شمارد .برنامه بال مي تواند بعنوان wcشما مورد توجه قرار گیرد.
اجازه دهید شمارنده ای را برای خطوط اضافه کنم.
>< #include < stdio.h ()void main } ;int c, nc = 0, nl = 0 ( while ) )c = getchar)(( != EOF } ;nc++ ;if )c == '\n'( nl++ { printf)"Number of characters = %d, number of lines = %d\n", ;(nc, nl شما مي توانید در مورد راههای شمارش تعداد کلمات در فايل فکر کنید؟
{
قابلیت های سطح بالی I/O
هنوز مي بینیم که printfخروجي فرمت بندی شده با stdoutرا بکار مي بردودر مقابل دستور خواندن از scanf ، stdinاست .نحو
آن
; ( scanf )“format string “ ,variables مانند printfاست .فرمت رشته ممکن است شامل فاصله ها يا تب ها باشد ( .چشم پوشي مي شود) کاراکترهای اسکي معمولي ،که
بايد آنها را با stdinمطابقت داد ،و تبديل مشخصات مانند printfدستورات معادل برای خواندن يا نوشتن رشته های کاراکتری موجود
است .آنها عبارتند از:
;(sprintf)string, "format string", variables ;(scanf)string, "format string", variables
محیط برنامه سازی لینوکس
175/322
اين کد را ترجمه و اجرا کنید؛ سپس ويرايشگری را برای خواندن فايل 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
نوشتن تابع های خودتان
يك تابع دارای طرح بندی زير مي باشد:
(فهرست نشانوند اگر لزم باشد) نام تابع
نوع بازگشتي )
{ ..........اعلن محلي ......... ...........دستورات ........... ; مقدار بازگشتي return {
اگر نوع بازگشتي حذف شده باشد C ،بطور پیش فرض از intاستفاده مي کند .مقدار بازگشتي بايد از نوع اعلن شده باشد.
يك تابع ممکن است بطور ساده يك وظیفه را بدون بازگشت هیچ مقداری اجرا کند .در اين حالت دارای طرح بندی زير مي باشد:
(فهرست نشانوند اگر لزم باشد ) نام تابع
void
} ...........اعلن های محلي ........ .........دستورات .......... {
يك مثال از فراخواني تابع xبه کد زير توجه کنید:
/* 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 /* call own function */ ;(n = n_char)string ;(printf)"Length of string = %d\n", n /* definition of local function n_char */
{
محیط برنامه سازی لینوکس
177/322
([]int n_char)char string } /* local variable in this function */ ;int n /* strlen)a( returns the length of */ /* string a */ /* defined via the string.h header */ ;(n = strlen)string (if )n > 50 ;("printf)"String is longer than 50 characters\n /* return the value of integer n */
;return n
{
نشانوند ها همیشه توسط مقدار درفراخواني های تابع رد مي شوند .يعني کپي های محلي مقادير نشانوند ها از روالها عبور مي کنند .هر
تغییر در نشانوند ها بطور دروني در تابع فقط در کپي های محلي نشانوند ها ايجاد مي شود.
بمنظور تغییر ( يا تعريف ) نشانوند درفهرست نشانوند ،اين نشانوند بايد بعنوان يك آدرس عبور کند ( ،در نتیجه الزام Cبرای تغییر
نشانوند واقعي در روال فراخواني).
بعنوان يك مثال به تعويض دو عدد بین متغیرها توجه کنید ،ابتدا اجازه دهید آنچه اتفاق مي افتد را اگر متغیرها توسط مقدار عبور کنند را با مثال نشان دهیم
>#include < stdio.h ;(void exchange)int a, int b /* WRONG CODE */
()void main } ;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
{
(void exchange)int a, int b } ;int temp ;temp = a ;a = b ;b = temp
محیط برنامه سازی لینوکس
178/322
;(" printf)" From function exchange: ;(printf)"a = %d, b = %d\n", a, b اين کد را اجرا کنید و ملحظه کنید که aو bعوض نشده اند :فقط کپي های نشانوند ها تعويض شده اند: البته روش صحیح انجام اين کار استفاده از اشاره گرهاست:
{
>#include < stdio.h ;( void exchange ) int *a, int *b /* RIGHT CODE */
()void main } ;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
{
( void exchange ) int *a, int *b } ;int temp ;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تعداد کل رشته ها را مي دهد ،بنابراين برابر است با تعداد نشانوندها به اضافه يك .برای مثال اگر شما 2 -g -x 3 q
a.out -iراتايپ کنید برنامه مقادير زير را دريافت مي کند.
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 (main)int argc, char** argv } ;int i ;(printf)"argc = %d\n", argc
محیط برنامه سازی لینوکس
180/322
(for )i = 0; i < argc; i++ ;([printf)"argv]%d[ = \"%s\"\n", i, argv]i
{
برنامه نويسان يونیکس قرار دادهای مشخصي در مورد چگونگي تفسیر فهرست نشانوندها دارند .آنها اجباری نیستند بلکه برنامه شما را بای استفاده و فهم ديگران آسانتر مي سازند .اول اينکه اصطلحات سوئیچ ها و کلیدها با کاراکتر « » -شروع مي شوند .اين باعث
مي شود که به آساني آنها را تشخیص دهید .سپس ۷بسته به سوئیچ ،نشانوندها ممکن است شامل اطلعاتي که بعنوان صحیح ،شناور يا
فقط بعنوان يك رشته کاراکتری نگه داشته شده اند تفسیر شوند .با اين قرار دادها ،رايجترين راه تجزيه فهرست نشانوند بوسیله حلقه
Forو يك دستور switchمي باشد. مانند زير:
>#include < stdio.h >#include < stdlib.h (main)int argc, char** argv } /* Set defaults for all parameters: */ ;int a_value = 0 ;float b_value = 0.0 ;char* c_value = NULL ;int d1_value = 0, d2_value = 0 ;int i /* Start at i = 1 to skip the command name. */ } (for )i = 1; i < argc; i++ /* Check for a switch )leading "-"(. */ } ('if )argv]i[]0[ == '- /* Use the next character to decide what to do. */ } ([switch )argv]i[]1 ;([a_value = atoi)argv]++i ;break
case 'a':
;([b_value = atof)argv]++i ;break
case 'b':
;[c_value = argv]++i ;break
case 'c':
محیط برنامه سازی لینوکس
181/322
;([d1_value = atoi)argv]++i ;([d2_value = atoi)argv]++i ;break
case 'd':
{
{
{
;(printf)"a = %d\n", a_value ;(printf)"b = %f\n", b_value ;(if )c_value != NULL( printf)"c = \"%s\"\n", c_value ;(printf)"d1 = %d, d2 = %d\n", d1_value, d2_value
{
دقت کنید که [ 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 */ */ */ /********************************/ /* Steve McMillan */ /* Written: Winter 1995 */ >#include < stdio.h >#include < stdlib.h
(void get_args)int argc, char** argv, int* a_value, float* b_value
محیط برنامه سازی لینوکس
182/322
}
int i; /* Start at i = 1 to skip the command name. */ for )i = 1; i < argc; i++( } /* Check for a switch )leading "-"(. */ if )argv]i[]0[ == '-'( } /* Use the next character to decide what to do. */ switch )argv]i[]1[( }
{
{
{
case 'a':
*a_value = atoi)argv]++i[(; break;
case 'b':
*b_value = atof)argv]++i[(; break;
default:
fprintf)stderr, "Unknown switch %s\n", argv]i[(;
{
main)int argc, char** argv( } /* Set defaults for all parameters: */ int a = 0; float b = 0.0; get_args)argc, argv, &a, &b(;
{
printf)"a = %d\n", a(; printf)"b = %f\n", b(;
جعبه هاي محاوره : واسط هاي گرافيكي۱۲ ولي هنوز مي خواهید برنامه شما قادر به تغییر مقادير متغیرهای مشخص،فرض کنید شما نمي خواهید با تفسیر خط فرمان مواجه شويد
محیط برنامه سازی لینوکس
183/322
در يك روش محاوره ای باشد .شما مي توانید برنامه را در يك سری خطوط ـ printf/scanfبرای امتحان کاربرد در مورد اولويت هايشان ساده کنید.
. .
. ;(" printf)"Please enter the value of n: ;(scanf)"%d", &n ;(" printf)"Please enter the value of x: ;(scanf)"%f", &x . . .
ومانند آن ،البته اين کار خوبي نخواهد بود اگر برنامه شما به عنوان بخشي از خط لوله ( )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 /* Define contents of dialog window */ ;(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 /* Display the window and read the results */ ;()read_dialog_window
محیط برنامه سازی لینوکس
184/322
/* Print out the new values */ ;(printf)"n = %d, x = %f\n", n, x
{
اين برنامه را با استفاده از نام مستعار 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کاراکترهای غیر قابلچاپ را در يك شکل
قابل فهم آشکار ميسازد :
ل واضحتر از visميباشد .اما sedهرگز برای فايلهای غیرمتني معني نميدهد: خروجي .sedاحتما ً
$ sed - n 1 x abc <<<--$
$ 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‘ ( .برای اسمبلر ميباشد) :
$ cc vis . c $ a .out hello world ctl-g helo world \ 007 ctl – d $ در حالت عادی شما بايد a.outرا مجدداً نامگذاری کنید .زمای که کار ميکند و يا از انتخاب – oاز ccبرای انجام آن به طور مستقیم
استفاده کنید :
محیط برنامه سازی لینوکس
188/322
output in vis not a .out خروجي در vis، a.outنميباشد.
vis . c
cc – o vis
$
تمرين 1ت .6ما تصميم گرفتيم كه جدولبنديها بايد كنار گذاشته شوند ،به جاي اينكه به صورت \ tيا يا \ 011آشكار شوند ،چون استفاده مهم ما از ، visپيدا كردن كاراكترهاي حقيقتاً نامبهم ميباشد تتت تجدولبنديها ،ت غيرتصويريها ،فاصلهها در انتهاي سطرها تو غيره Vis .را به گونهاي تغيير دهيد كه كاراكترهايي شبيه جدولبندي ،پس كج خط ،پس برد ،كاغذ ت خورد و غيره ،در اجراهاي قراردادي cخود \ t ، \ \ ، \ b ، \ fو غيره .پرينت شوندت توت تدرت تنتيجهت تفاصلههاي تخاليت تدرت تانتهايت تسطرهات تعلمتگذاري تشوند .آيات تشما ميتوانيد چنين كاري را بدون ابهام انجام دهيد؟ طرح خود را با sed - n 1 $مقايسه كنيد. تمرين 2ـ Vis .6را به گونهای تغییردهید که سطرهای بلند را در طول معقول تاکند .اين کار چگونه با خروجي غیر مبهم مورد نیاز در
تمرين قبلي برهم کنش ميکند؟
2ت6 ت آرگومانهاي برنامه : نسخةvis 2 زماني که يك برنامه cاجرا ميشود .آرگومانهای سطر فرمان ،به عنوان يك شماره argcو يا آرايه argvاز اشارهگرها ،برای رشتههای کاراکتری که شامل آرگومانها ميباشند در دسترس تابع mainقرار ميگیرند .بر طبق قرارداد ]argv ]0 ،خودش اسم فرمان است، بنابراين argc ،همیشه بزرگتر از صفر است؛ آرگومانهای مفید ] argv ]1[ … argv ] g r g c - 1هستند .به خاطر داشته باشید که
جهت دهي مجدد باـ < وـ > ،توسط شل انجام ميشود و نه توسط برنامههای منفرد ،بنابراين جهتدهي مجدد تأثیری بر تعداد آرگومانهای مشاهده شده توسط برنامه ندارد.
برای شروع عملکرد يا آرگومان ،با افزودن يك آرگومان انتخابي visرا تغییر ميدهیم ، vis-s :همه کاراکترهای غیر چاپي را خارج
ميکند به جای اينکه آنها را به طور مداوم نمايش دهد .اين انتخاب ،برای پاك کردن فايلها از ساير سیستمها مناسب است ،برای مثال،
سیستم هايي که از ( CRLFسطر خورد و سطر جديد) به جای يك سطر جديد به سطرها پايان ميدهند. */
(کاراکترهای جالب را آشکار ميسازد (نسخه / * vis : 2
> # include < stadio . b > # inclue < stype . h (main )argc , argv ; int argc ; [ ] char * argv } ; int c , strip = 0
if cargc > 1 & $ strcmp )argv ] 1 [ , ″ - s ″( = = 0 ; strip = 1 (while )) c – getcharc )1 ( ! = EOF
محیط برنامه سازی لینوکس
189/322
if )isassiicc( $ $, (( ‘ ) isprintcc( | | c = = ′ \ n ′ | | c = = ′ \ t′ | | c = ′ ; (putchar ) c (else if ) ! strip ; (print f ) ″ \ \ % 30″ , c ; (exit )0 {
جدول 6ـ 1ـ درشت ـ دستورالعملهاي آزمون کاراکتر <> ctype.b الفبايي A-Z ، a-z :
) isalpha )c
مورد باليي A – Z :
) isupper )c
مورد پائین a – z :
) islower ) c
رقم 9 :ـ 0
) isdigit ) c
رقم شانزده شانزدهي 9 :ـ 0
A–F
a–f
الفبايي يا رقم
)isalnum ) c
فاصله ،جدولبندی ،سطر جديد ،جدول بندی عمودی ،کاغذ ـ خورد ،بازگشت
غیر الفبايي ـ عددی ،يا کنترل يا فاصله قابل چاپ :هر تصويری کاراکتر کنترل : کاراکتر = < c
) isxdigit ) c
) ispunct ) c ) isprint ) c
c || 040 c < = 0 < = = 0177 = < 0177 0
) isspace ) c
Ascl :
iscntrl )c
)
isascii )c
)
، 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و بهینه سازی اتفاقي دست آمده از نوشتن مجدد به زبان اسمبلي را شرح دهید.
جدول 2ـ 6ـ تابعهاي استاندارد رشته رشته tرا به رشتة sپیوست ميدهد؛ sرا بر ميگرداند
)stract )s , t
اکثر کاراکترهای nاز tرا به sضمیمه ميکند
)strnact )s , t , n
tرا برای sکپي ميکند؛ sرا بر ميگرداند
)strcpy )s , t
دقیق ًا کاراکترهای nرا کپي ميکند؛ اگر لزم باشد padرا خالي ميکند
sو tرا مقايسه ميکند < , 0 ،و > 0را برای دو = = > ,برميگرداند اکثر کاراکترهای nرا مقايسه ميکند
)strncpy )s , t , n )strcmp )s , t )strncmp )s , t ,n
طول sرا بر ميگرداند
)strlen )s
اشارهگر را به اولین cدر sبر ميگرداند ،اگر Nullنباشد
)strchr )s , c
اشارهگر را بهآخرين cدر sبر ميگرداند ،اگر nullنباشد
)strrchr )s , c
اينها index ،و rindexبر روی سیستمهای قبلي هستند
ارزش عدد صحیح sرا بر ميگرداند
)atoi )s
ارزش مییز شناور sرا بر ميگرداند؛
)atof )s
مستلزم اعلن )atof )sدوگانه ميباشد.
اشارهگر را به بايتهای nاز حافظه برميگرداند ،اگر nullنتواند
)malloc )n
اشارهگر را به بايتهای nxmبرميگرداند ،برای صفر تنظیم ميکند
)calloc )n,m
اگر nullنتواند Malloc .و * calloc ، charرا بر ميگردانند حافظه آزاد تخصیص يافته توسط mallocيا calloc 3ت 6 ت دستيابي به فايل : نسخه3
free )p
)
vis
دو نسخه اول ،visورودی استاندارد را ميخوانند و خروجي استاندارد را مينويسند ،و هردو از شل منتج ميشوند .مرحله بعدی ،تغییر
visبرای دستیابي به فايلها از طريق اسامي آنها است .بنابراين
محیط برنامه سازی لینوکس $
191/322
… vis file 1 file 2
فايلهای نامگذاری شده را به جای ورودی استاندارد ،پويش ميکند .اگر چه آرگومانهای اسم فايل شايد وجود نداشته باشند اما ما
ميخواهیم ، visورودی استاندارد خود را بخواند .سوال اين است که چگونه فايلها را برای خوانده شدن مرتب کنیم ـ يعني اينکه ،
چگونه اسامي فايلها را به بیانهای I /Oمتصل کنیم که دقیق ًا دادهها را بخوانند.
قواعد ساده هستند .قبل از اينکه يك فايل بتواند خوانده يا نوشته شود ،بايد توسط تابع کتابخانه استاندارد يعنيـ Fopenباز شود.
،Fopenيك اسم فايل را ميگیرد (همانند tempيا ، )etc / passwdسیستمداری و انتقال را با کرنل انجام ميدهد و يك اسم دروني را که بايد در عملکردهای بعدی روی فايل استفاده شود ،بر ميگرداند.
اين نام دروني ،دقیقا ً يك اشارهگر ميباشد که اشارهگر فايل نام دارد ،برای ساختاری که شامل اطلعاتي در مورد فايل ميباشد ،مانند
مکان يك میانگیر ،موقعیت کاراکتر فعلي در میانگیر ،و اينکه آيا يك فايل خوانده يا نوشته ميشود و مواردی از اين قبیل .يکي از
تعاريف بدست آمده از طريق > ، <stdio.bبرای يك ساختار ميباشد که FILEنام دارد .اعلن برای يك اشارهگر فايل عبارت است از
; FILE * fp اين اعلن بیان ميکند که fpيك اشارهگر به يك FILEميباشد Fopen .يك اشارهگر را به يك FILEبر ميگرداند؛ يك نوع اعلن برای fopenدر > <stdio. bوجود دارد.
فراخاني واقعي برای fopenدر يك برنامه عبارت است از
chr
; * name , * mode اولين آرگومان ، Foppenنام فايل ،به عنوان يك رشته كاراكتر ميباشد .دومين آرگومان ،نيز
يك رشته كاراكتر ميباشد و نشان ميدهد كه شما چگونه از فايل استفاده ميكنيد و روشهاي مجاز ،خواندن ( ، ) ″r″نوشتن ( ) ″w″يا ضميمه كردن ( ) ″a″ميباشند.
اگر فايلي که شما برای نوشتن يا ضمیمه کردن باز ميکنید ،وجود نداشته باشد ،اگر امکانپذير باشد ،بوجود ميآيد .باز کردن يك فايل موجود برای نوشتن باعث ميشود که محتواهای قبلي ،حذف شوند .تلش برای خواندن فايلي که وجود ندارد ،يك خطا است و
همانند تلش برای خواندن يا نوشتن يك فايل ميباشد زماني که شما اجازه نداريد .اگر خطايي وجود داشته باشد ، fopen ،ارزش ل به صورت ( )* charدر > <stdio . hتعريف ميشود). اشارهگر بياعتبار را به صورت ( nullتهي) بر ميگرداند( .که معمو ً
مورد بعدی مورد نیاز ،روش خواندن يا نوشتن فايل ميباشد زماني که باز ميشود امکانات متعددی برای اين مورد وجود دارند ،که از آنها getcو ، putcسادهترين هستند ،getc .کاراکتر بعدی را از فايل ميگیرد.
)C = getc )fp
کاراکتری بعدی از فايل را که به عنوان fpبه آن استناد ميشود در cقرار ميدهد؛ و EOFرا برميگرداند ،زمني که به انتهای فايل ميرسد ، Putc .شبیه به getcميباشد :
)putc ) c , fp کاراکتر cرا بر روی فايل fpقرار ميدهد و cرا برميگرداند getc .و putc ، EOFرا برميگردانند ،اگر يك اشتباه رخ دهد.
زماني که يك برنامه آغاز ميشود ،سه فايل باز ميشوند و اشارهگرهای فايل برای آنها تهیه ميشوند .اين فايلها ،ورودی استاندارد ، خروجي استاندارد و خروجي خطای استاندارد هستند؛ اشارهگرهای فايل مربوطه،ـ stdin ، stdoutوـ stderrنامیده ميشوند .اين
اشارهگرهای فايل در
> ، < stdio . hاعلن ميشوند؛ آنها ميتوانند در هر جايي استفاده شوند که به همان منظور تايپ ، * FILEميتواند استفاده شود .اما
محیط برنامه سازی لینوکس
192/322
آنها ثابتها هستند و نه متغیرها ،بنابراين شما نميتوانید ،به آنها استناد کنید.
، ) ( getcharهمانند )getc )stdinمیباشد و ) putchar )cهمانند )putc c , stdoutميباشد .در حقیقت ،هر چهار تابع ،به عنوان
> < stdio . hتعريف ميشوند ،چون آنها با اجتناب از
يك يك تابع برای هر کاراکتر ،سريعتر اجرا ميکنند .به جدول 3ـ 6برای ساير تعاريف در > <stdio . hمراجعه کنید.
با برخي از مقدمات خارج از روش ،اکنون ما ميتوانیم سومین نسخه از vicرا بنويسیم .اگر آرگومانهای سطر فرمان وجود داشته
باشند ،آنها به ترتیب پردازش ميشوند .اگر آرگومانها وجود نداشته باشند ،ورودی استاندارد پردازش ميشود.
/ * vis : make funny characters visible )version 3( * /
> # include < stdio . b > # include < type . b ; int strip = 0 */ 1 ⇒ discarc special characters * / (main )argc , argv ; int argc ; [ ] char * argv } ; int i ; FILE * FP } (While )argc > 1 $ $ argv ]1[ ]0[ = = ′- ′ } ( [Switch )argv ]1[ ]1 case ′ s ′ : / * - s ; strip funny chars * / ; strip = 1 ; break default : fprintf )stderr , ″ % s : unknown arg % s \ n ″, ; argv ] 0[ , argv ]1[1 ;(exit )1 { ; argc - - ; argv + + { (if )argc = = 1 ;(vis )stdin else ( for ) i = l ; i < argc ; i + + } (if )) fp = fopen )argv ]i[ , ″r″ (( = = NULL fprintf )stderr , ″ % s : can’t open % s \ n″ , ;( [argv ]0[ , argv ] i ; (exit )1 } { else ; (vis )fp ; (fclose )fp {
محیط برنامه سازی لینوکس
193/322
; (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
پیغامهای خطا ،شروع به ناپديد شدن درون خطوط لولهای کردند).
تا حدوی اختیاری ،ما تصمیم گرفتیم که visاز سیستم خارج میشود اگر نتواند يك فايل ورودی را باز کند؛ چنین چیزی برای برنامهای
که اغلب به صو رت برهمکنشي استفاده ميشود و با يك فايل ورودی تنها ميباشد ،معقول است .شما ميتوانید برای طرح ديگر به
بحث و بررسي بپردازد.
تمرين 5ـ .6يك برنامه pritableبنويسید که نام هر فايل آرگومان را که شامل فقط کاراکترهای قابل چاپ ميباشد ،پرينت کند؛ اگر فايل شامل کاراکتر غیر قابل چاپ باشد ،اسم آن پرينت نشود Printable .در موقعیتهايي مانند اين ،مفید است :
pr ′ printable * ′ | pr
انتخاب 7ـ را برای معکوس کردن حس آزمون ،همانند grepوارد کنید.
$
Printableچه بايد انجام دهد اگر آرگومانهای اسم فايل وجود نداشته باشند؟ printableبه چه وضعیتي بايد برگردد؟
ورودی استاندارد
جدول 3ـ 6ـ برخي از تعاريف > < stdio . b stdin
خروجي استاندارد
stdout
خطای استاندارد
stderr
انتهای فايل :در حالت عادی 1ـ
EOF
نشانگر غيرمعتبر ؛ در حالت عادي °
NULL
استفاده شده برای اعلن اشارهگرهای فايل
FILE
اندازه نرمال میانگر ( I / Oاغلب 512يا )1024
BUFSIZ
يك کاراکتر از جريان FPباز ميگرداند ( ) getchar
کاراکتر cرا بر روی رشته fpقرار ميدهد ( put char ) c
)getc )fp )getc )stdin )putc )c , fp )putc ) c , stdout
صفر نميباشد زماني که انتهای فايل بر روی رشته fpقرار دارد
صفر نميباشد زماني که هر گونه خطا بر روی رشته fpقرار دارد
توصیفگر فايل برای رشته fp؛ به فصل 7مراجعه کنید
)feop )fp )ferror )fp )fileno )fp
4ت 6 ت يك چاپگر نمايشي در يك زمانP : تاکنون ما از catبرای بررسي فايلها استفاده کرديم .اما اگر يك فايل بلند باشد ،و اگر شما توسط يك اتصال دارای سرعت بال به سیستم خود متصل شده باشید ،cat ،خروجي را به گونهای تولید ميکند که بينهايت سريع خوانده شود ،حتي اگر شما با ctl-sو ctl- qسريع باشید.
به طور آشكارا ،بايد يك برنامه براي پرينت يك فايل در chunkهاي كوچك قابل كنترل وجود داشته باشد ،اما يك برنامه استاندارد وجود ندارد ،احتمالً به دليل اينكه سيستم اوليه يونيكس ،در روزهاي پايانههاي نسخه سختت (كاغذ) و سطرهاي ارتباطي كند نوشته
محیط برنامه سازی لینوکس
195/322
شده است .بنابراين ،مثال بعدي ما برنامهاي با عنوان Pميباشد كه يك فايل پرده پر را در يك زمان پرينت ميكند و منتظر جواب از كاربر ،پس از هر پرده نمايش و قبل از رفتن به پرينت بعدي ،ميماند ، ″P″( .يك اسم كوتاه و مناسب براي برنامهاي است كه ما آن را بسيار زياد استفاده ميكنيم). همانند ساير برنامهها p ،از فايلهای نامگذاری شده به عنوان آرگومانها ويا از ورودی استاندارد خود ميخواند :
$ p vis . c … $ grep ′ # define ′ * . ] ch [ | p … $
اين برنامه ،به بهترني نحو در زبان cنوشته ميشود ،چون اين برنامه در زبان cآسان است و در زبانهای ديگر دشوار است؛ ابزار استاندارد ،در ترکیب کردن ورودی از يك فايل يا لوله با ورودی پايانه ،مناسب نیستند.
طرح اساسي و بي پيرايه ،چاپ كردن ورودي در قطعههاي كوچك ميباشد .يك اندازه مناسب براي قطعه،ت 22سطر ميباشدت :كه اين اندازه ،اندكي كمتر از پرده نمايشت 24 سطريت تاكثرت تپايانههايت تتصويريت تميباشدت تو ت
1 3
تتازت تيكت تصفحهت تاستاندارد ت 66سطري
ميباشد .يك روش ساده تبراي اينكهت 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
/ * p : print input in chunks )version \( * / ># include < stdio . h # define PAGESIZE 22 char * programe ; / * program name for error massage * / (main )argc , argv ; int argc ; [ ] char * argv } ; int i ; FILE * fp , * efopen < 1
; [Programe = argv ]0 ( if ) argc = = 1 ; (print )stadin , PAGESIZE else } ( for ) i = l ; i < argc ; i + + ; (fp = < fopen )argv ]i [ , ″r″ ;(print )fp , PAGESIZE ;(fclose )fp { ;(exit )0 { زير برنامه ، efopenيك عملکرد بسیار عمومي را وارد ميکند .سعي کنید يك فايل را باز کنید؛ اگر امکانپذير نیست ،يك پیغام خطا را
پرينت کنید و خارج شويد .برای اينکه پیغامهای خطا را تشويق کنید که برنامه مزاحم (يا مزاحم شده) را شناسايي کنند efopen ،به يك برنامه رشته خارجي استناد داده ميشود که شامل نام برنامه ميباشد و در mainتنظیم ميشود.
/ * fopen file , die if )an.’t * /
(FILE * efopen )file , mode ; Char * file , * mode } ; ( ) FILE * fp , * fopen ; Extern char * programe
(if )) fp = fopen )file , mode(( ! = NULL ; return fp fprintf )stderr , ″ % s : can’t open file % s mode % s \ n ″ , ; ( programe , file , mode ; (exit )l
{
ما يك جفت از طرحهای ديگر را برای ،efopenقبل از فرو نشاندن بر روی اين برنامه ،بررسي کرديم .يکي از آنها ،قبل از چاپ کردن
پیام ،با يك اشارهگر تهي که خرابي و اشکال را نشان ميدهد ،آن را باز ميگرداند .چنین چیزی به شماره گیرنده انتخاب ادامه يا خروج
را ميدهد .طرحي ديگر efopen ،را با سهآرگومان تهیه ميکند و اين آرگومانها مشخص ميکنند که آيا بايد پس از شکست در باز کردن فايل بازگشت يا خیر .اما در اکثر مثالهای ما ،اشارهای برای ادامه وجود ندارد ،اگر نتوان به يك فايل دست يافت ،بنابراين نسخه
محیط برنامه سازی لینوکس
197/322
فعلي از ، efopenبهترين نسخه برای استفاده ميباشد . کار واقعي فرمان ، pدر printانجام ميشود.
Print )fp , pagesize( / * print fp in pagesize chunks * / ; FILE * fp ; Int pagesize } static int lines = 0 ; / * number of lines sofar * / ; [char buf ] BUFSIZ (while )fgets )buf , size of buf , fp( ! = NULL (if ) + + lines < page size ; (fputs )buf , stdout } 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را برای بازگرداندن اولین کاراکتر از پاسخ نوشتیم ،اما از آن ويژگي در اينجا استفاده نميشود.
)version 1( * /
ttyin ) ( / * process response from / dev / tty } ; [char buf ] BUFSIZE ; ( ) FILE * efopen Static FILE * tty = NULL (if )tty = = NULL
محیط برنامه سازی لینوکس
198/322
;( tty = efopen ) ″ / dev / tty ″ , ″r″ ( if )fgets )buf , BUFIZE , tty( = = NULL | | buf ]0[ = = ′ q ′ ; (exit )0 else / * ordinary line * / ; [return buf ]0
{
اشارهگر فايل ،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به شرح زير است :
ttyin ) ( / * process response from / dev / tty )version 2( * / } ; [char buf ]BUFSIZ ; ( ) FILE * efopen ; Static FILE * tty = NNUL (if )tty = = NULL ; ( tty = efopen ) ″ / dev / tty ″ , ″ r ″
محیط برنامه سازی لینوکس
199/322
} ( ; ; ) 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از لوله يا يك فايل خوانده شود ،فرمان ميتواند با ورودی خودش ،تداخل کند :
edرا از pميگیرد
$ cat / etc / passwd | p – 1 root : 3 D : f HR 5 KoB. 3 s : o : 1 : s . usr : / : ! ed
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 :
5ت 6 ت يك مثالpick : نسخه Pickدر فصل ،5به وضوح تواناييهای شل را گسترش ميدهد .نسخه cکه اکنون بیان ميشود ،تا حدودی متفاوت از نسخه c
موجود در فصل 5ميباشد .اگر اين نسخه دارای آرگومانها باشد ،آنهاهمانند قبل پردازش ميشوند .اما اگر تنها آرگومان ’ـــ ‘ مشخص
شود ، Pick .ورودی استاندارد آن را پردازش ميکند.
اگر هیچ آرگوماني وجود نداشته باشد ،چرا ورودی استاندارد خوانده نميشود؟ نسخه دوم فرمان zapرا در بخش 6ـ 5در نظر بگیريد
:
kill $ SIG ′ pick [ ′ ps – ag | egrep ″ $ * ″ ′ \ | awk ′ }print $ 1 {′ چه اتفاقي ميافتد اگر طرحـ egrepچیزی را تطبیق نکند؟ در اين حالت،ـ pickهیچ آرگوماني ندارد و شروع به خواندن ورودی
، zapدر يك روش گیج کننده ،خراب ميشود .نیاز به يك آرگومان آشکار ،يك روش آسان برای غیر استاندارد خود ميکند؛ فرمان مبهم کردن چنین موقعیتهايي ميباشد و قرارداد ’ـــ ‘ از catو ساير برنامهها ،نشان ميدهد که چگونه آن را تشخیص دهیم.
/ * pick : offer choice on each argument * / > # include < stdio. h char * programe ; / * program name for error message * /
(main )argc , argv ; int argc ; [ ] char * argv } ; int i ; [char buf ] BUFSIZ ; [programe = argv ]0 if )argc = = 2 $ $ strcmp )argv ]1[ , ″__″ ( = = o ( / * pick _ * / } (while )fgets )buf , sizeof buf , stdin( i = NULL
محیط برنامه سازی لینوکس
201/322
buf ] strlen )buf( –1 [ = ′ \ o ′ ; / * drop newline * / ; ( pick )buf
{
( for ) i = l ; i < argc ; i + + ; ( [pick )argv ]i ; ( exit ) 0
else
{ pick )s( / * offer choice of s * / ; char * s } ; ( fprintf )stderr , ″ % s? ″ , s (if )ttyin ) ( = = ′ y ′ ; ( print f ) ″ % s \ n ″ , s { pickبرای انتخاب آرگومانها به طور برهمکنشي يك مسیر ساده را در يك برنامه متمرکز ميکند .چنین چیزی نه تنها يك کار مفید را فراهم ميکند ،بلکه همچنین نیاز به انتخابهای برهمکنشي را بر روی ساير فرمانها کاهش ميدهد.
تمرين 10ـ 6ـ با توجه به ، pickآيا نیاز به rm – iوجود دارد ؟
6ت 6 ت روي خطاها و خطازدايي ل يك برنامه نوشته باشید ،با تصور يك خطا آشنا هستید .راه حل خوبي برای نوشتن رمز بدون خطا وجود ندارد به جز اينکه اگر شما قب ً مراقب باشیم که يك طرح ساده و تمیز به وجود آوريد و آن را به دقت اجرا کنید و آن را تمیز نگه داريد ،همچنانکه آن را تغییر ميدهید.
ابزار اندکي از يونیکس وجود دارند که به شما در پیدا کردن خطاها کمك ميکنند ،اگر چه هیچ کدام از آنها واقعا ً عالي نميباشند .اما
برای شرح آنها ،ما به يك خطا نیاز داريم و همه برنامههای موجود در اين کتاب کامل هستند .بنابراين ،ما يك خطای نمونه ايجاد
ميکنیم.
تابع ارائه شده pickدر بال ،را در نظر بگیريد .در اين جا نیز وجود دارد ،اما اکنون دارای يك خطا ميباشد( .نیازی نیست که دوباره آن را از اول تکرار کنیم).
pick ) s( / * offer choice of s * / ; Char * s } ; ( fprint ) ″ % s ? ″ , s ( if )ttyin ) ( = = ′ y ′ ; ( print f ) ″ % s \ n ″ , s {
محیط برنامه سازی لینوکس
202/322
اگر ما آن را کامپايل و سپس اجرا کنیم ،چه اتفاقي ميافتد؟
pick . c – o pick ( ( $ pick * . c $
)memory fault )ore dumped
آن را بررسي کنید
ناپديد ميشود !
“ ” memory faultبه اين معناست که برنامه شما سعي ميکند به بخشي از حافظه مراجعه کند
که مجاز نميباشد .معمول ً به اين معناست که يك اشارهگر ،به جايي نامعقول اشاره ميکند ، ”Bus error“ .تشخیصي ديگر با همین
معني ميباشد و اغلب با پويش کردن يك رشته پايان نیافته ،بوجود ميآيد.
“ ، ” cor dumpedبه اين معناست که کرنل ،وضعیت برنامه اجرا کنندة شما را در يك فايل با نام coreدر فهرست ذخیره ميکند.
شما همچنین ميتوانید يك برنامه را مجبور کنید که با تايپ ، \ctl – 1حافظه اصلي را خالي کند ،البته اگر در پیش زمینه اجرا ميشود و يا با نرمال ، kill-3حافظه اصلي را خالي کنید ،البته اگر در پیش زمینه ميباشد.
دو برنامه برای نوشتن در حافظه وجود دارد adb ،و .sdbهمانند اکثر خطا زداها ،آنها مرموز ،پیچیده و ضروری هستند Adb .در
هفتمین ويرايش وجود دارد؛ sdbدر اکثر نسخههای اخیر سیستم در دسترس ميباشد .يکي از اين دو برنامه ،مطمئنا ً در سیستم وجود دارند.
ما در اينجا فقط به حداقل استفاده قطعي از هر کدام از آنها ميپردازيم :پرينت کردن يك
، stack traceکه تابعي است که زماني اجرا شد که برنامه به پايان رسید ،تابعي که آن را فراخواند و مواردی از اين قبیل .اولین تابع
نامگذاری شده در ،stack traceدر جايي است که برنامه وجود داشت زماني که خاموش شد. برای اجرای يك stack traceبا ، adbفرمان c $ ،ميباشد :
به adbاستناد ميکند
adb pick core $
stack traceرا درخواست ميکند
c $
) - stroutو 0و 011و )011200 01155772 ° adjust : fillch : 060542 ( و 0و 011و doprnt ) 011200 01155722 (و f print f )0177345 011200
011200 0177345 °
0177345
0177234 از سیستم خارج شويد
035 01 °
iop : fmt : args : (pick )0177345 s: (و main )0177234 035 argc : argv : i: 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
stack traceرا درخواست ميکند
* t ( ) 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پس از يك زماني طولني از ويرايش ،ارزشمند است و اطمینان ميدهد که شما هر اخطاری را که ميدهد ،درك ميکنید.
7ت 6 ت يك مثالzap : ، zapکه به صورت انتخابي ،فرآيندها را حذف ميکند ،برنامه ديگری است که ما آن را به عنوان يك فايل شل در فصل ، 5ارائه داديم .مشکل عمده با اين نسخه،سرعت است zap :فرآيندهای زيادی را بوجود ميآورد که به کندی آنها را اجرا ميکند؛ و بويژه برای
برنامهای که فرآيندهای خاطي را حذف ميکند .نوشتن مجدد zapدر ، cآن را سريعتر ميکن .اما ما قصد نداريم که کل کار را در اينجا
انجام هیم :ما هنوز از psبرای پیدا کردن اطلعات فرآيند استفاده ميکنیم Ps .خیلي آسانتر از خارج کردن اطلعات از کرنل ميباشد و
قابل انتقال نیز ميباشد ، zap .يك لوله را با psبر روی انتهای ورودی باز ميکند و از روی آن ميخواند به جای اينکه از يك فايل
بخواند .تابع ( ،popen )3مشابه به fopenمي باشد .به جز اينکه اولین آرگومان ،يك فرمان است به جای اينکه يك اسم فايل باشد. همچنین يك pcloseوجود دارد که ما در اينجا به آن نیازی نداريم.
/ * zap : interactive process killer * / > # include < stadio . h > # include <signal. h ; char * programe / * program name for error message * / char * ps = ″ ps – ag ″ ; / * system dependent * / ( main ) argc , argv ; int argc ; [ ] char * argv } ; ( ) FILE * fin , * popen ; [Char buf ] BUFSIZ ; int pid
; [progname – argv ]0 } (if )) fin = popen )ps , ″ r ″ (( = = NULL ; (fprint f )stderr , ″ % s : can’t run % s \ n ″ , progname , ps ; (exit )1 { ; (fgets )buf , size of buf , fin / * get header line * / ; ( fprintf )stderr , ″ % s ″ , buf ( while )fgets )buf , size of buf , fin( ! = NULL } ( if )argc = = l | | strindex )buf , argv ]1[ (> = 0 buf ] strlen )buf ( – 1[ = ′ \ 0 ′; / * suppress \ n * / ; (fprintf )stderr , ″ % sp ″ , buf } ( if )ttyin ) ( = ′ y ′ ;sscanf )buf , ″ % d ″ , $ pid0 ; (kill )pid , SIGKLL { {
محیط برنامه سازی لینوکس
205/322
; (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وجود نداشته باشد. strindex )s , t ( / * return index of tins , - 1 if none * / ; char * s , * t } ; int i , n ; (n = strlen )t ( for ) i = o ; s ]i[ ! = ′ \ o ′ ; i + + ( for )strncmp )sti , t , n ( = = 0 ; return i ; return – 1 { جدول 4ـ 6ـ تابعهايي را که عموماً استفاده ميشوند ،از کتابخانه استاندارد I / Oرا به طور خلصه بیان ميکند.
تمرين 11ـ 6ـ zapرا به گونهای تغییر دهید که هر تعداد از آرگومانها بتوانند ذخیره شوند .همانگونه که نوشته شد zap ،در حالت
عادی ،سطر را بر طبق خودش به عنوان يکي از انتخابها ،پژواك ميکند .آيا بايد اينگونه باشد؟ اگر نه ،برنامه را متعاقباً تغییر دهید :نکته
.)get pid )3 :
محیط برنامه سازی لینوکس
206/322
تمرين 12ـ 6ـ يك تابع )fgrep )1در اطراف strindexبسازيد .زمانهای اجرا برای جستجوهای پیچیده را با هم مقايسه کنید ،ده کلمه را در يك سند بیان کنید .چرا fgrepسريعتر عمل ميکدن؟
8ت 6 ت يك برنامه مقايسه فايل برهم كنشidiff : يك مشکل عمومي ،داشتن دو نسخه از يك فايل ميباشد ،که تا حدودی متفاوت هستند و هر کدام شامل بخشي از يك فايل مطلوب
ميباشند؛ چنین چیزی اغلب زماني بوجود ميآيد که تغییرات به طور مستقل توسط دو فرد متفاوت انجام شوند Diff .به شما ميگويد
که چگونه فايلها با هم تفاوت دارند ،اما diffبه طور مستقیم به شما کمك نميکند،اگر شما بخواهید بخشي از قسمتهای اولین فايل و برخي از قسمتهای دومین فايل را انتخاب کنید.
در اين بخش ،ما يك برنامه idiff )diffبرهم کنشي) مينويسیم که هر قطعه از خروجي diffرا ارائه ميدهد و اختیار انتخاب بخش «
»fromانتخاب بخش « »toيا ويرايش بخش را پیشنهاد ميکند.
، idiffقطعات انتخاب شده را در يك ترتیب صحیح .در يك فايل با عنوان idiff . outقرار ميدهد .که با توجه به اين دو فايل
ميباشد :
file 1 : this is a tegt of your skill and comprehension diff produces
file 2: this is hot a test of our ability
جدول 4 ت 6 ت تابعهاي مفيد و استانداردI / O
فايل < را باز ميكند؛ وضعيت r″ ، w″ ، a″براي
)fp = fopen ) s , mode
خواندن ،نوشتن ،ضمیمه کردن )NULLرا برای خطا باز ميگرداند)
کاراکتر را ميگیرد؛ ) ( getc ) st din( , get charميباشد
)c = gctc )ff
کاراکتر را قرار ميدهد؛ )putc ) c , std out( , put char ) cميباشد کاراکتر را بر روی فايل ورودی fpقرار مي دهد؛ حداکثر يك char
)putc )c , fp )ungetc )c , fp
ميتواند در يك زمان به عقب برگردد.
کاراکترها (از ، a) , … , ( stdinبر طبق fmt
scanf )fmt , al
ميخواند .هر aiبايد يك اشارهگر باشد.
EOFهای بازگشت يا تعداد میدانها معکوس ميشوند.
از فايل fpميخواند از فايل sميخواند
)… , f scanf )fp )… , ss can f )s
)… ,
محیط برنامه سازی لینوکس
207/322
… , alرا بر طبق fmtفرمت ميکند و بر روی stoutپرينت ميکند
)… , print f )fmt , al
… را بر روی فايل fpپرينت ميکند
)… , fprint f )fp
… را درون رشته ،sپرينت ميکند
)… , sprintf )s
حداکثر nکاراکتر را از ، fpدرون sميخواند
)fget s )s , n , fp
NULLرا در انتهای فايل باز ميگرداند.
رشته sرا بر روی فايل fpپرينت ميکند
)f puts )s , fp
هر گونه خروجي میانگیر شده ،بر روی فايل fpرا پاك ميکند
فايل fpرا ميبندد
)f flush )fp )f close )fp
لوله را برای فرمان sباز ميکند Fopen .را مشاهده کنید لوله fpرا ميبندد
)fp = popen )s , mode )pclose )fp
فرمان sرا اجرا ميکند و منتظر کامل شدن آن باقي ميماند
)system )s
$ diff file 1 file 2 2c2 < a test …… > not a test 4,6c4,5 < your < skill < and comprehension …… > our > ability $ :مانند زير ميباشد idiffيك مکالمه با اولین تفاوت
را انتخاب ميکند ( < ) کاربر نسخه دوم دومین تفاوت
$ idiff file 1 file 2 2c2 < a test ……… > not a test > ? 4,6c4 ,5 < your < skill < and comprehension …… > our
محیط برنامه سازی لینوکس
208/322
را انتخاب ميکند (>) کاربر اولین نسخه خروجي در اين فايل قرار ميگیرد
> 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بوده باشد ،در نتیجه ،میانگیر ويراستار به اين صورت به نظر ميرسد :
هر چیزی که درون فايل توسط edنوشته ميشود ،چیزی است که وارد خروجي نهايي ميشود.
your skill and comprehesion …… our ability
در آخر ،هر فرماني ميتواند از طريق گريز با ! 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 * /
( main )argc , argv ; int argc ; [ ] char * argv } ; ( ) FILE * fin , * fout , * f 1 , * f 2 , * efopen ; ( ) char buf ] BUFSIZ[ , * mktemp ; char * diffout = ″ idiff. x x x x x x ″ ; [ progname = argv ] 0 } (if )argc ! = 3 ; (fprintf )stderr , ″ usage ; idiff file 1 file 2 \ n ″ ; (exit )1 {
محیط برنامه سازی لینوکس
209/322
f1 = efopen )argv ]1[ , ″ r ″ ( ; f2 = efopen )argv ]2[ , ″ r ″ ( ; fout = efopen ) ″ idiff . out ″ , ″ w ″ (; mktemp )diffout( ; sprintf )buf , ″ diff % s > % s ″ , argv ]1[ , argv ]2[ , diffout( ; system )buf( ; fin – efopen )diffout , ″ r ″ (; idiff )f1 , f2 , fin , fout( ; unlike )diffout( ; printf ) ″ % s output in file idiff . out \ n ″ , progname ( ; exit < 01 ; { آرگومان خود را روی هم، 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 ( ; unlike )tempfile( ;
/ * can fail on very long files * /
محیط برنامه سازی لینوکس
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
PAGESIZEرا در profileخود تعريف ميکنید :
PAGESIZE = 36 Export PAGESIZE
زير برنامهت ( ، )″ var ″ getenvبه جستجوي محيطي براي متغيرت varشل ميپردازد و ارزش خود را به صورت يك رشته از كاراكترها باز ميگرداند و يا به صورت ،NULLاگر متغير تعريف نشود .با توجهت ، getenvتغييرت ، pآسان است .همه آن چيزي كه مورد نياز است ،اضافه ه اصلي ميباشد. كردن يك جفت از اعلنها و يك فراخواني براي getenvدر آغاز زير برنام / * p : print input in chunks )version 3( * / …… ; ( ) char * p , * getenv ; [progname = argv ]0 if )) p = getenv )″ PAGESIZE″ (( ! = NULL ; (pagesize = atoi )p } ( تتت if )argc > 1 $ $1 argv ]1[ ]0[ = = ′ ;( [pagesize = atoi ) $ arg v ]1[ ]1 ; argc - - ; argv + +
{ …… آرگومانهای انتخابي ،پس از متغیر محیط پردازش ميشوند .بنابراين هر اندازه آشکار از صفحه ،يك اندازه ناآشکار از صفحه را
نميپذيرند.
تمرين 17ـ 6ـ idiffرا به گونهای تغییر دهید که به جستجوی محیط برای نام ويراستاری بپردازد که استفاده ميشود .برای استفاده از PAGESIZE ، 2و ، 3غیره را تغییر دهید.
تاريخچه و نكات كتابشناسي کتابخانه استاندارد ، I/Oپس از کتابخانه قابل انتقال از میك لسك ،توسط دنیس ريتچای ،طراحي شد .هدف هر دو بسته نرم افزاری،
فراهم کردن روشهای ساده استانداردی است که برنامهها بتوانند توسط آنها ،بدون تغییر از سیستمهای يونیکس به سیستمهای
غیريونیکس حرکت کنند.
طرح pبر اساس يك برنامه از هنری اسپنسر ميباشد.
adbتوسط استیو بورن sdb ،توسط هوارد کاتسف و lintتوسط استیو جانسون نوشته شد.
،Idiffکما بیش بر اساس يك برنامه ميباشد که در اصل توسط جومارانزانو نوشته شد Diff .خودش توسط داگ میکلوری نوشته شد و بر اساس الگوريتمي ميباشد که مستقل ً توسط هارولد استون و توسط وايني هانت و تام سیزماسنکي اختراع شد( .به کتاب « يك
الگوريتم سريع برای محاسبه طولنيترين نتايج عمومي» نوشته ] .w.هانت و G.Tسیز مانسکي ، CACM ،ماه مي 1977مراجعه
کنید) .الگوريتم ، diffدر کتاب D.Mمیلکوری و W.Jهانت با عنوان « يك الگوريتم برای مقايسه فايل متفاوت» 41 ،گزارش علمي
محیط برنامه سازی لینوکس
214/322
و تکنیکي بل لبز ،1976 ،توصیف ميشود .به نقل قول از میکلوری « من حداقل سه آلگوريتم کامل متفاوت را قبل از آلگوريتم نهايي
بررسي کردهام diff .يك مورد ناب و اصیل نه فقط برای تعیین صلحیت ـ محض در يك برنامه ميباشد ،بلکه همچنین آن را مجدداً بررسي میکنید تا جايي که صحیح باشد».
محیط برنامه سازی لینوکس
215/322
فصل هشتم فراخوانیهاي سیستمی اين فصل بر پائین ترين سطح برهمکنش با سیستم عامل يونیکس تاکید دارد – فراخوانیهای سیستم .اين فراخوانیها ،وروديهايکرتل
هستند آنها مسیرهای ساده ای هستندکه سیستم عامل فراهم مي کند و هر چیزديگری بر بالی آنها ساخته مي شود .
ما بخش های متعدد مهمي را تحت پوشش قرار مي دهیم .اولین بخش ،سیستم 1/0است ،زير بنايي تحت زير برنامه های کتابخانه
مانند . pntc,fopenما در خصوص سیستم فايل ،بويژه فهرست ها و winodبیشتر صحبت خواهیم کرد .بعدا به بحث و بررسي در
خصوص فرآيندها مي پردازيم .چگونه برنامه ها از درون يکبرنامه اجرا مي شوند .پس از آن ،ما در خصوص علمت ها و وقفه ها
صحبت مي کنیم :
چه اتفاقي مي افتدزماني که شما کلید Deleteرا فشار مي دهید و چگونه از آن به طور معقول در يك برنامه استفاده مي کنیم .
همانند فصل 6بسیاری از مثالهای ما ،برنامه های مفیدی هستند که بخشي از ويرايش هفتم نمي باشند .حتي اگر آنها مستقیما برای
شما مفید نباشند ،شما بايد چیزی از خواندن آنها ياد بگیريد و آنها بايد ابزار مشابهي را بیان کنند که شما مي توانید برای سیستم خود بسازيد .
جزئیات کامل در مورد فراخوانیهای سیستم در بخش 2از کتاب راهنمای برنامه نويس يونیکس وجود دارند و اين فصل ،مهمترين
بخشها را توصیف مي کند ،اما در مورد تمامیت آن چیزی ارائه نمي دهد
I/O 17داراي سطح پائین : پائین ترين سطح ، I/Oورود مستقیم به سیستم عامل مي باشد .برنامه شما فايلها را درقطعاتي با اندازه مناسب مي خواند و مي نويسد .
کرنل ،داده های شما را در قطعاتي ،میانگیر مي ند که طرحهای پیراموني و عملیات های برنامه ها را برروی طرحها ،به منظور بهینه کردن عملکرد آزاد برای همه کاربرها تطبیق دهند .
توصيف گران فايل همه ورودی و خروجي از طريق خواندن و نوشتن فايلها انجام مي شود ،چون همه طرحها پیراموني ،حق پايانه شما ،فايلهايي در
سیستم فايل مي باشند .مفهوم اين عبارت اين است که يك اتصال منفرد همه ارتباط بین يك برنامه و طرحهای پیراموني را انجام مي دهد .
در عمومي ترين مورد ،قبل از خواندن يا نوشتن يك فايل ،لزم است که سیستم خود را برای انجام آن ،مطلع سازيد ،فرآيندی که بازکردن فايل نامیده مي شود .اگر شما قصد نوشتن بر روی يك فايل را داريد .بوجود آوردن آن فايل نیز مي تواند لزم باشد .سیستم
صحت انجام کار شما را کنترل مي کند (آيا فايل خارج مي شود ؟ آيا شما مجاز به دستیابي به آن هستید ؟) و اگر همه چیز درست باشد .يك عدد صحیح مثبت را که توصیف گر فايل نامیده مي شود ،باز مي گرداند .هر موقع که 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منجر به آرايشهای پیش فرضها
مي شوند ،اما تخصیص های فايل توسط شل تغییر مي کنند و نه توسط برنامه ( .برنامه خودش مي تواند اين تخصیص ها را مجددا مرتب کند ،اگر بخواهیم ،اما اين مورد نادر است .
I/Oفايل – خواندن و نوشتن تمام ورودی و خروجي توسط دوفراخواني سیستم انجام مي شود 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
Vax-11.750 8/188 3/19 6/2 0/1 6/0 6/0
Pdp= 11.70 0/271 9/29 8/3 3/1 2/1 0/1
(Tim )user + system, sec
SIZE 1 10 100 512 1024 5120
اندازه بلوك ديسك 512 ،بايت بر روی سیستم PDP-11و 1024بايت بر روی VAXمي باشد .تقريبا برای فرآيندهای متعدد مجاز مي باشد که در يك زمان به يك فايل دست يابند و حقیقتا ،يك فرآيند مي تواند نوشته شود ،زماني که فرآيندی ديگر خوانده مي شود
اگر اين چیزی نباشد که شما مي خواهدی مي توان نگران کننده باشد ،اما گاهي اوقات مفید است .اگر چه ،يك فراخواني برای read
،صفر را باز مي گرداند و در نتیجه علمت های انتهای فايل را باز مي گرداند ،اما اگر داده های بیشتری بر روی آن فايل نوشته شود ،
readبعدی ،بايتهای بیشتری را در دسترس مي يابد .اين مشاهده ،مبنای برنامه ای است که redslowنامیده مي شود برنامه ای که خواندن ورودی خود را ،بدون توجه به اين که آيا به انتهای فايل مي رسد يا نه ،ادامه مي دهد readslow.برای تماشای پیشرفت يك برنامه مناسب است .
#slowprog > tem 5213 process - id # redslow <tem: grep sometting به عبارت دير کي برنامه کند که خروجي را در يك فايل تولید مي کند ؛ readslowو شايد در همکاری با برنامه ای ديگر ،انباشته
محیط برنامه سازی لینوکس
218/322
شدن داده ها را مشاهده کند .
از نظر ساختاری redslow ،مشابهه با catمي باشد ،به استثنای اينکه ،به جای خارج شدن از سیستم ،حلقه سازی مي کند ،زماني که
با انتهای جريان ورودی مواجه مي شودـ redslow .بايد ازـ I/Oدارای سطح پائین استفاده کند ،چون زير برنامه های کتابخانه
استاندارد ،پس از اولین پايان فايل EOF ،را گزارش مي دهند .
/*readslow:keep reading, waiting for more*/ # define SIZE 512/*arbitrary */ []main [char buf]SIZE ; int n }(; ;)for while ))n=read )0,buf , sizeof buf(( >01 ;(write )1,buf , n ;(sleep )10 { تابع sleepباعث مي شود که برنامه برای چند ثانیه خاص ،مسکوت باقي بماند و اين تابع در )sleep )3توصیف مي شود .ما نمي خواهیم ، readslowدر فايل ،به خاطر جستجوی مداوم برای داده های بیشتر ،بسته شود ،چون چنین چیزی در زمان cpuبسیار
پرهزينه خواهد بود .بنابراين اين نسخه ، readslowورودی خود را تا انتهای فايل کپي مي کند ،اندکي مي خوابد و سپس دوباره
تلش مي کند .اگر داده های بیشتری برسند ،زماني که اين نسخه خواب است .توسط readبعدی خوانده خواهد شد .
تمرين . 7-1يك آرگومان – nبه readslowاضافه کنید ،سپس زمان خواب پیش فرض مي تواند تا nثانیه تغییر کند .برخي از
سیستم ها يك انتخاب –( fبرای همیشهـ ) برایـ tailتهیه مي کنند که تابعههایـ tailرا باتابعهایـ readslowترکیب مي کندـ .در خصوص اين طرح توضیح دهید .
تمرين . 7-2چه اتفاقي برای readslowمي افتد اگر فايلي که خوانده مي شود کوتاه شود ؟چگونه شما آن را ثابت مي کنید ؟ نکته در خصوص fstatدر بخش 7-3مطالعه کنید .
ايجاد فايل – بازكردن ،ايجاد كردن ،بستن ،مواردي متفاوت غیر از فايلهای پیش فرض ورودی ،خروجي و خطای استاندارد ،شما بايد آشکارا ،فايلها را به منظور خواندن يا نوشتن آنها بازکنید .دو فراخواني سیستم برای اين کار وجود دارند . 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
فايلهای متني قبلي ،تهیه مي شود .
; Int perms ;(Fd = creat )name , perms ، Creatيك توصیف گر فايل را بر مي گرداند اگر قادر به ايجاد فايل متني با عنوان nameباشد و اگر قادر به چنین کاری نباشد -1 ،
را برمي گرداند .اگر فايل وجود نداشته باشد Creatآن را با اجازه های مشخص شده توسط آرگومان permsبوجود مي آورد .اگر فايل از قبل وجود داشته باشد Creat .طول آن را تا صفر کوتاه مي کند ؛ اين کار يك خطا برای ايجاد فايلي که از قبل وجود دارد ،
نمي باشد (اجازه ما ،تغییر نخواهد کرد ) بدون توجه به permsيك فايل ايجاد شده ،برای نوشتن باز مي باشد .
همانگونه که در فصل 2توصیف شد .نه بیت از اطلعات پشتیباني همراه با يك فايل وجود دارند که خواندن ،نوشتن و اجازه اجرا را
کنترل مي کنند ،بنابراين يك عدد هشت هشتي سه رقمي برای مشخص کردن آنها مناسب است .برای مثال 0755خواندن .نوشتن
واجازه اجرا را برای مالك مشخص مي کند و نیز اجازه خواندن و اجرا کردن را برای گروه و هر کسي ديگری مشخص مي کند .عدد
صفر اصلي را فراموش نکنید ،که چگونگي مشخص شدن اعداد هشت هشتي در cمي باشد .
برای شرح دراينجا يك نسخه ساده شده از cpوجود دارد .سادگي اصلي آن ،اين است که نسخه ها فقط يك فايل را کپي مي کند و به
دومین آرگومان اجازه نمي دهد که يك فهرست باشد .عیب ديگر اين است که نسخه ها ،جوازهای فايل مبدا را حفظ نمي کند ؛ ما
نشان مي دهیم که چگونه اين مورد را چاره کنیم.
/*cp:minimal version*/ #include cstdio-hs # define PERMS 0644 /*RW for owner , R for group , others*/ ; char * progname main)arg,argv(/*cp:copy fito f2 */ ;int argc ;[ ] char * grgv ; int f1, f2 , ;[char buf ]BUFSIZ [programe = qrgv ]0 (if )argc !=3 ;(error )usage:%s from to , progname if ))f 1= open )argv ]1[ , 0((=-1 ;([error )cant create %s , argv]2 (while ))n=read )f,buf , Bufsiz((>0 ;(if )write error , )char *(0 ;(exit )0 { ما errorرا در بخش فرعي بعد مورد بحث و بررسي قرار مي دهیم . دراينجا يك محدوديت (اساسا حدود 20به مشاهده NOFILEدر > <sys/param.hsبپردازيد) ،در تعداد فايلهايي وجود دارد که يك برنامه مي تواند به طور همزمان باز کند .بر همین اساس ،هر برنامه ای که قصد دارد فايلهای زيادی را پردازش کند ،بايد برای استفاده
مجدد از توصیف گران فايل آماده باشد .فراخواني سیستم ، closeارتباط بین يك اسم فايل و يك توصیف گر فايل را از بین مي برد و
توصیف گر فايل را به منظور استفاده توسط فايلي ديگر ،آزادمي کند .اتمام يك برنامه از طريق exitيا بازگشت از برنامه اصلي ،همه فايلهای باز را مي بندد .
محیط برنامه سازی لینوکس
220/322
فراخواني سیستم unlikeيك فايل را از سیستم فايل پاك مي کند . پردازش خطا – error فراخواني های سیستم مورد بحث واقع شده در اين بخش ،و در حقیقت همه فراخوانیهای سیستم مي توانند منجر به خطا شوند . معمول آنها ،يك خطا را با برگرداندن يك ارزش -1نشان مي دهند .گاهي اوقات فهمیدن اينکه چه خطای ويژه ای رخ داده است .
خوب است برای اين منظور همه فراخوانیهای سیستم ،زماني که مناسب است يك عددخطا را در يك عدد صحیح خارجي جا مي گذارند که errorنامیده مي شود . (معني اعداد متعدد خطا ،در مقدمه بخش 2از کتاب راهنمای برنامه نويس يونیکس ،فهرست وار بیان مي شود ) با استفاده از error
برنامه شما برای مثال مي تواند ،تعیین کند که آيا تلش برای بازکردن يك فايل با شکست مواجه شده است ،به خاطر اينکه فايل وجود نداشته است و يا به خاطر اينکه شما مجاز به خواندن آن نبوده ايد .
همچنین يك آرايه از رشته های کاراکتر sys-errlistوجود دارد که توسط errorمشخص مي شود و اعداد را به يك رشته معني دار ترجمه مي کند .نسخه errorما ،از اين ساختار داده ها استفاده مي کند :
Error )s1 , s2( /*print error message and die */ ; Char * s1,*s2 } ; extern int error , sys-nerr extern char *sys- errlist ] [ ,*progname (if )progname ;(fpritf)stderr , %s , programe ;(fprintf )stderr,s1,s2 (if )errno>&&errno<sys-nerr ;[fprint )stderr,)% s ( , sys-errlist]errno ;(fprint f)stderr,in ;(exit )1 { ، errnoدر ابتدا صفر است و بايد همیشه کمتر از sys-nerrباشد errno .برای صفر ريست نمي شود .زمانیکه همه چیز خوب است .اما شما بايد آن را پس از هر errorريست کنید اگر مي خواهید برنامه خود را ادامه دهید . در اينجا ،چگونگي آشکار پیامهای خطا با اين نسخه از cpوجود دارد :
&cp foo bar (cp:cant open foo )No such file or directory
& date>foo ;chmod o fooيك فايل غير قابل خواندن بسازيد & cp foobar (cpi : cant open foo )permission denied
محیط برنامه سازی لینوکس
221/322
&
دستيابي تصادفي – lseek 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
تمرين efopen . 7-4از فصل 6برای فراخواني errorمجددا بنويسید .
27سيستم فايل :فهرست هاي راهنما موضوع بعدی ،چگونگي حرکت از طريق سلسله مراتب فهرست راهنما مي باشد .برای چنین چیزی در حقیقت از فراخوانیهای جديد
سیستم استفاده نمي شود ،فقط برخي از فراخوانیهای قبلي در يك متن جديد قرار مي گیرند .ما با نوشتن يك تابع باعنوان 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
<sys/types.bيافت مي شود ،جايي که بايد قبل از > <sys/dir.bباشد .
عملکرد ، spnameدر مسیر مستقیم است ،اگر چه ،موقعیت هايي زيادی برای رفتن به سمت راست وجود دارد .فرض کنید اسم
فايل d1/ d2 / f/مي باشد .عقیده اصلي ،جدا کردن اولین جزء( )/مي باشد ،سپس جستجوی فهرست راهنما ،برای اسمي است که
نزديك به جزء بعدی ( )d1مي باشد ،سپس جستجوی فهرست راهنما،برای چیزی نزديك d2مي باشد و به همین ترتیب ،تا جايي که يك تطبیق برای جزء يافت شود .اگر در هر مرحله به يك داوطلب قابل قبول ،در فهرست راهنما نباشد ،جستجو متوقف مي شود .
ما اين کار را به سه تابع تقسیم کرده ايم spnameخودش اجزاء مسیر را از هم جدا مي کند و آنها را در يك اسم فايل « تا اندازه ای دارای بهترين تطبیق مي سازد .جزء جديد mindistرا فرامي خواند که به جستجوی يك فهرست راهنمای مشخص برای فايلي مي
پردازد که به مدلهای فعلي ها نزديك مي باشد و با استفاده از يك تابع سوم spdistفاصله بین دواسم را محاسبه مي کند .
/*spname:return correctly spelled filename*/ */ ;*spname )oldname , newname(char *oldname ,*newname *refurns -1 if no reasonable match to oldname, * 0 if exat match, * 1 if corrected . * stores corrected name in newname */ ># include <sys/ types.b ># include <sys /dir.b (spname )oldname,newname ;char*oldname,*newname } ;[char *p,guess ]DIRSIZ+[, best ]DIRSIZ+1 ;char * new = newname , *old = oldname }( ; ; )for while )*old==/(/*skip slashes*/
;new++=old ++
*new =\0 if )*old=10( /*exat or corrected */ ;return strcmp )oldname,newname( !=o p=guess ;/*copy next component into guess*/ (for ); *old!=/ &&*old !=10,old ++ (if )p<guess +DIRSIZ ; *P++=*old ;*p= IO (if )mindist )newname , guess,best(>3 return-1 , /*hoplless */
for )p=best ; new =p++;(/*add to
/*of newname*/ { mindist)dir,guess,best(/*search dir for guess*/
;char dir,guess,*best
} /*set best , return distance 0003*/
محیط برنامه سازی لینوکس
224/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
casel: /*corrected */ ;(fprintf )stderr, 1 %s \, buf (if )ttyin ) ( ==n ; break ; argv ]I[ = buf /*fall through...*/ case 0: /*exact match */ ;(fp= efopen cargv ]I[ , r ;(print )fp,pagesize ;(fclose )fp { ;(exit )0 {
تصحيح تلفظ ،چيزي نيست كه به صورت كوركورانه براي هر برنامه اي كه از اسامي فايلها استفاده مي كند ،بكار رود ،تصحيح تلفظ ،با pبه خوبي كار مي كند ،چون pبرهم كنش مي باشد ،اما براي برنامه هايي كه برهم كنش نمي باشند ،مناسب نيست .
تمرين . 7-5شما چقدر مي توانید برای انتخاب بهترين تطبیق ، spnameبر روی روشهای اکتشافي ،پیشرفت کنید ؟ برای مثال ،
احمقانه است که با يك فايل متطم به گونه ای برخورد کنیم که گويا يك فهرست راهنما مي باشد و چنین چیزی مي تواند با نسخه فعلي رخ دهد .
تمرين . 7-6نام ، txهر گونه tcرا که در انتهای فهرست راهنما رخ مي دهد ،برای هر کاراکتر ، cتطبیق مي کند .آيا شما مي توانید يك ارزيابي بهتراز فاصله را اختراع کنید ؟ آن را اجرا کنید و مشاهده کنید که چگونه با کار برهای واقعي کار مي کند .
تمرين mindist . 7-7در هر زمان يك مدخل از فهرست راهنما را مي خواند .آيا pبه صورت هوشمندانه سريعتر اجرا مي شود ،اگر خواندن فهرست راهنما ،در مقامات بزرگتر انجام شود:
تمرين spname . 7-8را به گونه ای تغییر دهید که نامي را بازگرداند که يك پیشوند از يك نام دلخواه باشد ،اگر تطبیق نزديکتری يافت نشود .چگونه پیوندها بايد شکسته شوند ،اگر اسامي متعددی وجود داشته باشند که همگي پیشوند را تطبیق کنند ؟
تمرين . 7-9چه برنامه های ديگری ،مي توانند از spnameبهره مند شوند به يك برنامه خود اتکا را طراحي کنید که تصحیح را برای آرگونهای خود بکار برد ،قبل از اينکه آنها را در طول برنامه عبور دهند ،مانند
&...fix progfilenames
آيا شما مي توانید يك نسخه از cdرا بنويسید که از spnameاستفاده کند که چگونه آن را نصب مي کنید ؟
37سيستم فايل inodes : در اين بخش به ما بحث در خصوص فراخوانیهايي از سیستم مي پردازيم که به سیستم فايل و بويژه با اطلعاتي در خصوص فايلها ،
مانند اندازه ،تاريخ ها ،اجازه ها و مواردی از قبیل مي پردازند .اين فراخوانیهای سیستم به شما اين امکان را مي دهند که همه
اطلعاتي را بدست آوريد که ما در خصوص آنها در فصل 2صحبت کرديم .
مي خواهیم وارد خود inodesشويم .بخشي از inodeتوسط يك ساختار با عنوان statتوصیف مي شود که در ><sys /stat .b
تعريف مي شود :
محیط برنامه سازی لینوکس
227/322
Struct stat /*structure returned by stat */
{ Dev-t Ino-t short short short short Dev-t Off-t Tim-t Time-t Time-t
St-dev; St-ino; St-mod; St-nlink; St -uid ; St-gid ; St - rder ; St - size ; St-atime; St-mtime; St-time;
/*device of inode */ /*inode number*/ /*mode bits*/ /*number of links tofile*/ /*owners u serid*/ /*owners groug id */ /*for special files*/ /*file size in characters*/ /*time file last read */ /*time file last wnttenor created*/ /*time file or inode last changed*/
{ همانگونه که، < تعريف مي شوندsys/stat.b> درino-t , dev-t تايپهايي مانند. توضیح داده مي شوند، اکثر فايلها توسط کافت ها تعاريف، شامل يك مجموعه از پرچم هايي است که فايل را توصیف مي کنند و برای سهولتst-mode ورودی. بال توصیف شد
: < مي باشندsys/stat.b> پرچم نیز بخشي از فايل
محیط برنامه سازی لینوکس
228/322
# define s-IFMI 0170000 /*type of file */ # define S- IFDIR 0040000 /*directory */ # define S-IFCHR 0020000 /*characterspecial*/ #define S-IFDLK 0060000 /*block special*/ #define S-IFREG 0100000 /*regular*/ #define S- ISUID 0004000 /*set useridon exection/* #define S-ISGID 0002000 /*set group idon execution */ #define S-ISVTX 0001000 /*save swapped texteven after use*/ #define S-IREAD 0000400 /*read permission , owner */ #define S-IWRITE 0000200 /*write permission,owner*/ #define S-IEXEC 0000100 /*execute/search permission,owner*/ يك اسم فايل را ميstat . پردازش مي شودfstat , stat توسط يك جفت از فراخوانیهای سیستم با نامهای، برای يك فايلInode . ) را باز مي گرداند اگر يك فقط خطا وجود داشته باشد-1 را برای آن فايل باز مي گرداند (ياinode گیرد واطلعات
: که به اين صورت است،) file همان کار را از يك توصیف گر فايل برای يك فايل باز انجام مي دهد (که از يك اشاره گر، Fstat
Char *name; Int fd; Struct stat stbuf ; Stat )name ,& st buf(; Fstat )fd , & st buf (;
. پر مي کندfd برای اسم فايل و توصیف گر فايلinode رابا اطلعاتstbuf ساختار
، آغاز مي کنیمcheckmail ازc اکنون با يك نسخه. ما مي توانیم نوشتن برخي از کدهای مفید را آغاز کنیم، با وجود همه اين حقايق
عبارت « شما پست الکترونیکي داريو » را، checkmail ، اگر فايل بزرگتر شود. برنامه ای که صندوق پستي شما را نگاه مي کند
به خاطر اين مي باشد که شما نامه پستي را، از قرار معلوم، (اگر فايل کوتاه تر شود. پرينت مي کند و زنگ را به صدا در مي آورد
چنین چیزی کامل به عنوان قدم اول مناسب است و شما مي توانید ممتاز. ) خوانده و حذف کرده ايد و پیغامي درخواست نمي شود /* checkmail :watch users mailbox*/ # include <stdio .bs> # include <sys / types.bs> # include <sys/ stat-h> char * progname ; char *maildir = /usrlspool/mail , /*sys tem dependent*/ main )argc,argr( int argc; char *argv ] [ ; } struct stat buf ; char *name , * getlogin ) ( ; int lastsize=0 progname = argv ]0[ ; if ))narne = get/ogin )(( == null( error )cant get name , )char*(0(; if )chdir )maildir(== -1(
. تر باشید زماني که اين برنامه کار مي کند
محیط برنامه سازی لینوکس
229/322
;( error )cant cd to % s , muildir } ( ; ;) for if )stat )name , & buf( == -1(/k no mailbox */ ; buf.st -size =0 (if )buf .st-size >last size ;(fprint f)stderr,lnyou have mail loov ln ;lastsize = buf.st - size ; (sleep )40 {
{ تابع )getlogin )3اسم Loginشما را باز مي گرداند و يا اگر نتواند nullرا باز مي گرداند chdirlkmail .با فراخواني سیستم chdir ،به فهرست پستي تغییر مي کند ،بنابراين ،فراخوانیهای بعدی ، statنبايد هر فهرستي از ريشه را برای فهرست پستي جستجو کنند .
شما بايد maildirرا به گونه ای تغییر دهید که بر روی سیستم شما تصحیح شود .ما check mailرا نوشتیم برای اينکه بررسي کنیم آيا صندوق پستي وجود ندارد ،چون اکثر نسخه های ، mailصندوق پستي را حذف مي کنند اگر خال باشد .ما اين برنامه را در فصل
5نوشتیم برای اينکه تا اندازه ای ،حلقه های شل را شرح دهیم .
اين نسخه فرآيندهای متعددی را بوجود مي آورد ،در هر زمان که به صندوق پستي نگاه مي کند ،بنابراين مي تواند بیشتر از بار
سیستمي باشد که شما مي خواهید .نسخه cيك فرآيند منفرد مي باشد که يك statرا بر روی فايل در هر دقیقه انجام مي دهد .چه قدر اين فرآيند برای اجرای checkmailدر زمینه درتمام زمان ،ارزش دارد؟ ما آن را به خوبي در يك ثانیه در هر ساعت اندازه گیری کرديم ،و میزان آن ،آنقدر پائین است که اهمیتي ندارد .
: SVيك شرح از كنترل خطا ما بعدا قصد داريم برنامه ای را با عنوان 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
& random filename يك خط منتخب به صورت تصادفي از فايل تولید مي کند .با دادن اسامي افراد به فايل random ،مي تواند در يك برنامه با عنوان scapeyoatاستفاده شود ،برنامه ای که برای اختصاص به اشتباه ارزشمند مي باشد :
& cat scapegoat ! echo it s all random peoples foult &scape goat !its all kens a fault &
اطمینان حاصل کنید که ، randomبدون توجه به توزيع طول سطرها ،درست مي باشد .
تمرين . 7-16اطلعات ديگری در inodeنیز وجود دارد ،بويژه ديسك به جای نشان مي دهد که بلوکهای فايل قرار دارند .فايل >
<sys / ino.bرا بررسي کنید ،سپس برنامه icatکه فايلهای مشخص شده توسط عدد inodeو طرح ديسك را مي خواند ،را بنويسید ( .اين برنامه ،فقط زماني کار مي کند که ديسك قابل خواندن باشد ) .تحت چه شرايطي icat ،مفید است ؟
47فرآيندها اين بخش ،توصیف مي کند که چگونه يك برنامه را از داخل برنامه ای ديگر ،اجرا کنیم .آسانترين راه برای انجام آن ،با زير برنامه
کتابخانه استاندارد ، system .مي باشد .که در فصل 6ذکر شد اما سانسور شد system .يك آرگومان را مي گیرد ،يك سطر فرمان دقیقا به همان صورتي که در پايانه تايپ مي شود (به جز برای سطر جديد در انتها ) و آن را در يك زير شل ،اجرا مي کند .اگر سطر
فرمان بايد از قطعات ساخته شود ،توانايي های فرمت درون حافظه sprintfمي تواند مفید باشد .در پايان اين بخش ،ما يك نسخه
ايمن تر از systemرا برای استفاده توسط برنامه های برهم کنش نشان مي دهیم ،اما در ابتدا ما بايد قطعات را از چیزی که ساخته مي
شود بررسي کنیم .
ايجاد فرآيند داراي سطح پائين – execup , execlp مهمترين عملکرد ،اجرای برنامه ای ديگر بدون بازگشت و با استفاده از فراخواني سیستم 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
; [progname = argv ] 0 (if )argc<2 ; (error )dsage : % s file name ])md[ ,progname (if )) fd=open )argv ]1[ , 0(( == -1 ;([error )cant open % s , argv ]1 ; ( fstat )fd , &stbuf }(while )stbuf . st -mtime != old - time ; old - time = stbuf.st - mtime ; (sleep )6-
محیط برنامه سازی لینوکس
چنین برنامه ای هم execlpو هم execvpرا شرح مي دهد .
234/322
; ( fstat )fd , & stbuf { if )argc = =2(} /*copy file */ ; (exedp )cat , cat , argv ]1[ , )char *(0 ;( [ error )can't execute cat % s ,argv ]1 } {else /*run process */ ; [cxecvp cargv ]2[ , & argv ]2 ;( [error )can't execute % s , argv ]2 { ; (exit )0 {
ما اين طرح را انتخاب کرديم ،چون مفید است ،اما ساير گونه ها قابل قبول هستند .برای مثال wail file ،مي تواند ،بازگشت را به
سهولت امکان پذير کند ،پس از اينکه فايل ،تغییر را متوقف کرده است .
تمرين watek file . 7-17رابه گونه ای تغییر دهید (تمرين )7-12که دارای همان ويژگي wait fileباشد :اگر فرماني وجود ندارد ،
، watch fileفايل را کپي مي کند و در غیر اين صورت فرمان را اجرا مي کند .آيا wait file , watch fileمي توانند دارای يك رمز
مبدا باشند؟ توجه ]argv]0 :
كنترل فرآيندها – wait , fork مرحله بعدی بدست آوردن مجدد کنترل پس از اجرای يك برنامه با 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نباشد .
. 57علئم و وقفه ها اين بخش در رابطه با چگونگي پرداختن به علئم(مانند وقفه ه ا ) به طور دقیق ،از دنیای خارج و با اشکالت برنامه مي باشد .
اشکالت برنامه اساسا از مراجع غیر مجاز حافظه ،اجرای ساختارهای ويژه يا خطاهای ممیز شناور بوجود مي آيند .عمومي ترين علئم دنیای خارج ،وقفه مي باشد که زمان فرستاده مي شود که کاراکتر 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
signal /)SIGINT , onitr (; /*reset for next interrupt */ ;(printf )\nlnterrupt\n long jmp )sjbuf , 0( ; /*return to saved state */ { فايل > <set jmp.hتايپ jmp-bufرا به عنوان يك هدف بیان مي کند که در آن موقعیت stackمي تواند ذخیره شود و ، sjbufبه
عنوان يك چنین هدفي بیان مي شود .تابع )set jmp )3يك رکورد از جايي را ذخیره مي کند که برنامه در آن اجرا مي شود .
ارزشهای متغیرها ،ذخیره نمي شوند .زماني که يك وقفه رخ مي دهد ،يك فراخوان به سمت زير برنامه onitrرانده مي شود ،که مي
تواند يك پیام را پرينت کند ،پرچم ها را تنظیم کند و يا هر چیز ديگری انجام دهد longjmp .به عنوان يك آرگومان يك هدف ذخیره
شده توسط setjmpرا مي گیرد و کنترل را برای موقعیت پس از فراخواني setjmpمجددا ذخیره مي کند .بنابراين کنترل (و سطح ، ) stackبه جايي در زير برنامه اصلي ،بر مي گردند ،جايي که حلقه اصلي وارد مي شود .
توجه داشته باشید که signalدوباره در onitrتنظیم مي شود ،پس از اينکه يك وقفه رخ مي دهد چنین چیزی لزم است :علئم به طور خودکار برای عملکرد پیش فرض خود ريست مي شوند زماني که رخ مي دهند .
برخي ازبرنامه هايي که مي خواهند ،علئم را به سهولت آشکار سازند ،نمي توانند در يك نقطه قرادادی ،برای مثال در وسط روز
آمدسازی يك ساختار پیچیده از داده ها متوقف شوند .راه حل ،داشتن يك زيربرنامه وقفه برای تنظیم يك پرچم و بازگشت به جای
فراخواني exitيا longjmpمي باشد .اجرا ،در نقطه ای ادامه مي يابد که دقیقا متوقف شده است و پرچم وقفه مي تواند بعدا آزمايش
شود .
يك پیچیدگي همراه با اين روش وجود دارد .فرض کنید برنامه پايانه را مي خواند ،زماني که وقفه فرستاده مي شود .زير برنامه مشخص شده ،به موقع فراخوان مي شوند اين زيربرنامه ،پرچم خود را تنظیم مي کند و باز مي گردد .اگر حقیقتا درست باشد ،همان گونه که ما در بال عنوان کرديم که اين اجرا ،در نقطه ای که دقیقا قطع شده است دوباره از سرگرفته شود برنامه خواندن پايانه را تا
جايي ادامه مي دهد که کاربر سطر ديگری راتايپ کند .اين رفتار گیج کننده است ،چون کاربر نمي داند که مي خواند و ظاهرا ترجیح
مي دهد که علمتي داشته باشد که به طور مداوم موثر باشد .برای حل اين مشکل ،سیستم readرا پايان مي دهد ،اما با يك حالت خطا ،که نشان مي دهد چه اتفاقي افتاده است ، errno :برای EINTRتنظیم مي شود و در ><errno.h برای نشان دادن يك فراخواني سیستم متوقف شده ،تعريف مي شود.
بنابراين ،برنامه هايي که متوقف مي شوند ،دوباره اجرا را از سر مي گیرند ،پس از اينکه علئم بايد برای خطاهای ايجاد شده توسط
فراخوانیهای سیستم متوقف شده آماده شوند ( .سیستم برای تماشای readها از يك پايانه wait ،و ، pouseفراخوان مي شود ) . چنین برنامه ای مي تواند از رمزی مانند رمز زير استفاده کند ،زماني که ورودی استاندارد را مي خواند :
># include <errno .h ; extern int errno ……… (if )read )0,& c,1(<=0 /*EOF or interrupted */ if )errno = = EINTR ( } /*EoF caused by interrupt */ errno = 0 ; /*reset for next time */ ……… } {else /*true end of file */ ……… يك ظرافت نهايي برای به خاطر سپردن وجود دارد ،زماني که گیرنده علمت با اجرای ساير برنامه ها ،ترکیب مي شود .برنامه ای را
محیط برنامه سازی لینوکس
240/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
#define SIG-DEL )int)*( ) 1(0 # define SIG -IGN )int )*( )1(1
هشدارها فراخواني سیستم )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
فصل 9توسعه برنامه سيستم UNIXدر واقع محيطي جهت طراحي و توسعه برنامه است .در اين فصل در مورد ابزارهايي كه بالخص براي طراحي و توسعه برنامه مناسبند صحبت مي كنيم .ابزار ما يك برنامه باارزش و متسري براي زبان برنامه نويسي در حد توان Basicمي باشد .از آنجا كه يك زبان نماينده اي از مشكلتي است كه در برنامه هاي بزرگ پيش مي آيد ، قصد داريم مراحل توسعه يك زبان را مطرح كنيمت .علوه براين مي توان به بسياري از برنامه ها به عنوان زبانهايي نگاه كرد كه يك ورودي سيستماتيك داخلي را به يكسري عمليات و خروجيهاي پشت سرهم تبديل مي كند ،بنابراين قصد ابزارهاي توسعه زبان را بيان كنيم . در اين فصل دروس خاصي راجع به مطالب زير را مطرح خواهیم کرد :
: Yacc-يك مولد تجزيه گر ( ، )parserبرنامه ای که با يك بیان گرامری زبان جداکننده تولید مي کند .
: Makeبرنامه ای برای تعیین و کنترل فرآيندهايست که يك برنامه پیچیده با آنها کامپايل : Lex-برنامه ای شبیه ، yaccبرای ساخت تحلیلگرهای واژه ای .
مي شود .
در ضمن مواردی نظیر چگونگي مواجهه با يك پروژه ،اهمیت شروع يك برنامه ،توسعه تدريجي زبان و استفاده از ابزارهای مختلف
را مطرح مي کنیم .
زبان را در شش مرحله توسعه خواهيم دادت .حتي اگر تا انتهاي شش مرحله نيز پيش نرويد ،هر يك از مراحل به تنهايي آموزنده و مفيد خواهد بود .توسعه يك برنامه دقيقاً به ترتيب اين شش مرحله خواهد بود .اين مراحل عبارتند از : •ماشین حساب چهار عمل اصلي ،شامل / ، × ، - ، +و پرانتز ،که برروی اعداد اعشاری عمل مي کند .در هر خط يك عبارت تايپ مي شود و ارزش آن فور ًا چاپ مي شو .
•متغیرها با اسامي aتا ، zاين مرحله علمت منفي از عبارت و حساسیت به خطاها را نیز در برمي گیرد .
•نامهاي متغيرها با طول دلخواه ،توابع داخلي exp,sinوت ، ...ثوابت ثابتي نظير ( 1 Tعدد nبه دليل محدوديتهاي تايپي به صورت 1 Tنمايش داده شده است . ) و يك اپراتور نمايي. •تغييرت تدرت تتوابع تداخليت .براي تهر تدستورت ( )statumentكدي تتوليدت تمي تشود تو سپس تبه تجاي تبرآورد تسريع تتفسير تمي تشودت .هيچت تويژگيت featureجديدي اضافه نمي شود اما نهايتًا به مرحله ( )5مي انجامد . •جريان كنترل uelse :و ، whileعبارات هم گروه با { }andو اپراتورهاي رابطه اي ... نظير > . ... , . . . < , •توابع وعمليات برگشتي به همراهت آرلگانهايشان .در اين مرحله دستوري نيز براي ورودي و خروجي -----و اعداد اضافه كرده ايم .
زبان حاصل از اين 6مرحله در دو فصل 9توضیح داده شده است .در اين فصل از اين زبان به عنوان مثال اصلي در ارائه نرم افزار تهیه
محیط برنامه سازی لینوکس
244/322
راهنمای UNIXاستفاده شده است .پیوست ( )2راهنمای مرجع است .
از آنجايي كه در نوشتن صحيح يك برنامه مفادين جزئيات زيادي بايد مدنظر قرار گيرد ،اين فصل بسيار طولني است .فرض ما بر اين است كه خواننده زبان Cرا درك مي كند و نسخه اي از جلد دوم راهنماي برنامه نويس UNIXرا در دست دارد ،چرا كه در اين جا مجالي براي توضيح تمامي جزئيات نيست .توجه كنيد و خودتان را آماده كنيد كه دوباره اين فصل را مطالعه كنيدت .تمامي كدهاي مورد نياز براي نسخه پاياني را در پيوست 3 آورده ايم ،بنابراين به راحتي مشاهد خواهيد بود كه اجزاء چگونه در تناسب با يكديگر قرار گرفته اند . زمان زيادي را صرف كرديم تا نام مناسبي براي اين زبان بيابيم اما هرگز به نتيجه مطلوب دست نيافتيم .نهايتًا hocرا برگزيديم كه از “ ’’high order calculatorگرفته شده است . بنابراين نسخه ها hoc 2, hoc 1و ...مي باشند . 81مرحلة : 1ماشين حساب چهار عمل اصلي :
اين بخش توليد hoc 1را توضيح مي دهد و اين برنامه ،برنامه اي است كه تواناييهاي معادل يك ماشين حساب جيبي با امكانات محدود را فراهم مي كند و البته به راحتي آن حمل نمي شود .اين برنامه فقط چهار تابع / ، × ، - ، +را دارد ( به علوه پرانتز را هم كه مي تواند به دلخواه وارد عبارت شود شامل مي شود ) كه ماشين حسابهاي جيبي با قابليتهاي محدود ارائه مي دهندت .اگر پس از يك عبارتت RETURNتايپ كنيد ،جواب حاصل در خط بعد چاپ خواهد شد.
محیط برنامه سازی لینوکس
245/322
قواعد ( )grammarsاز زمانيكه فرم Backus- Naurبراي Algolبه وجود آمد ،زبانها باقواعد منطقي بيان شده اند .قواعد hoc 1در نمايش اختصاري شان كوچك وساده اند . expr \n list expr \n NUMBER expr + expr expr - expr expr * expr expr / expr ()expr
list : 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
{ ( ) Yyparse ) ( } parser ,Which calls yylex
اين مورد كه yaccيك فايل Cبه جاي فايل كامپايل شده
0
ت مي سازد ،طريقه معمول
yacc . 4از ------- yet another comilerگرفته شده است .اين مورد ،توصیفي توسط نويسنده اش ، Steve Johnsonبرروی تعدادی از برنامه هايي که در زمان
تولید yaccوجود داشت (حدود )1972مي باشد .
محیط برنامه سازی لینوکس
247/322
برخورد يونيكس استت .اين تشيوه كه در آن توليد شده قابل حمل و انتقال به تساير فرآيندهاست منعطف ترين شيوه ممكن است .خود yaccابزاري قدرتمند است .لذا هر چند ممكن است آموختن yaccتلش زيادي را بطلبد اما نتيجه مثبت اين تلش به دفعات ديده مي شود .تجزيه گرهايي كه با yaccتوليد مي شوند ،كوچك ،كارآ و صحيح هستند ( .هرچند صحت عمليات معنايي برعهده خود شماست ) .با بسياري از مشكلت واضح تجزيه اتوماتيك برخورد مي شود .برنامه هاي شناخت زبان براحتي ساخته مي شوند و (مهمتر اينكه ) به موازات پيشرفت بيان زبان به كرات قابل اصلحند . برنامه مرحله ( )1
كد مرجع براي hoc1شامل گرامري به همراه عمليات ،يك برنامه مستقل واژه اي و يك mainمي باشد كه همگي در فايل hoc.yقرار دارندت ( .اسامي ت فايلهاي yaccبهت yختم مي شوندت .اما اين نحوه نامگذاري مرسوم ،برخلفت ccو cبا خودت yaccتحصيل تنمي شود ) .بخش گرامري ،نيمه اول hoc.yاست :
اطلعات جديد زيادی در اين خطوط وارد شده است .قصد نداريم که هر جزئیات اين بخش را توضیح دهیم و همچنین قصد نداريم نحوه عمل تجزيه گر را بیان کنیم .برای کسب اطلعاتي در اين زمینه مي توانید به راهنمای yaccمراجعه کنید .
قوانين يك درميان با Iجدا مي شوند .هر قانون گرامري مي تواند عمل مربوط به خود را داشته باشد .اين قانون زماني اجرا مي شود كه نمونه اي از آن در ورودي شناسايي شود .يك عمل ،مجموعه اي از عبارات cاست كه در براكت قرار گرفته اند . }and{ .با يك تعمل ت،ت ( $nمانندت $1ت،ت ، $2ت ) ...دال تبرت تمقداري تاست تكهت تبهت توسيلةت nامين تجزء
محیط برنامه سازی لینوکس
248/322
برگردانده مي شود و $$مقداري است كه به عنوان مقدار كل قانون برگردانده مي شود . بنابراين به عنوان مثال ،در قانون {; expr : NUMBWER }$$ ::: $ 1 $ 1مقداري است كه با شناسايي NUMBERبرمي گردد و اين مقدار به عنوان مقدار exprبرمي گردد .رابطه خاص $s :::$ 1قابل حذف است زيرا $$هميشه برابر $فرض مي شود مگر اينكه صراحتًا مقداري ديگري به آن نسبت داده شود . در سطح بعد ،زماني که قانون
}; }$$::: $ 1 +$ 3
expr : expr ΄ +΄ expr
' ' است ،مقدارت ، exprمجموع مقادير دو جزءت exprاست .توجه كنيد كهت ¿ $ 2 ,¿ت است .
هرجزء شماره گذاري مي شود . در سطحي بالتر ،سطر جديديت ¿ { n تبه عبارت افزوده مي شود ،به عنوان يكت list شناساييي شده و مقدار آن چاپ مي شودت .اگر آخر ورودي ساختار اينچنيني داشته باشد ،فرآيند تجزيه به وضوح متوقف مي شود .يك listممكن است يك رشته ()string خالي باشد .به اين ترتيب به خطوط ورودي خالي نيز عمل مي شود . وروديت yaccفرم خاصي نداردت .فرمي كه ما استفاده مي كنيم ،فرمت توصيه شده استاندارد استت .در اين چنين صورت ،عمل شناسايي با تجزيه ورودي ،برآورد فوري عبارت را نيز به همراه دارد .در موارد پيچيده تر (شامل hoc 4و نسخه هاي پس از آن ) ، فرآيند تجزيه براي اجراهاي بعدي كه توليد مي كند .بهتر است كه تجزيه را به صورت يك درخت تجزيه ( )parse treeمشابه شكل 1-8تصوير كنيم ومقادير را به صورتي كه محاسبه مي شوند و از برگهاي اين درخت به سمت ريشه رشد مي كنند ببينيم . '
'
محیط برنامه سازی لینوکس
249/322
شكل : 1-8درخت تجزيه گر براي
23∗4
مقادير قوانیني که کامل شناسايي نشده اند روی يك پشته ( )stckذخیره مي شوند .به اين ترتیب مقادير از يك قانون به ديگری انتقال
مي يابند .نوع داده های اين پشته معمولً يك nt/است اما از آنجا که بر اعداد اعشاری عمل مي کنیم بايد پیش فرض را در نظر بگیريم .
بیان
#define YYSTYPE double
نوع پشته را به صورت نوع مضاف ( )doubleتنظیم مي کند .
گروههايت تتركيبيت تكهت تبات تتحليلت تگرت تواژهت تايت تشناساييت تميت تشوندت تبايدمشخص شوند مگر اينكه تك كاراكتري مثل
'¿−¿' ,' ¿ ¿
باشند .تعريف token %
يك يا چند مورد از اين گروهها را تشريح مي كند .ارتباط چپ يا راست در صورتت تلزومت تيات تاستفادهت تازت left%يا right %بهت تجايت token %مشخصت تمي شود و ارتباط چپ به اين معني است كه a-b-cبه صورت ( a-b(-cتجزيه مي شود نه به صورت ت ت ( . )a-)b-cاولويت به وسيله مرتبه ظاهري تعيين مي شود .
-نشانه ها در تعريف يکسان بالترين اولويت را دارند .نشانه هايي که بعداُ معرفي مي شوند اولويت بالتری دارند
.در اين روش انتخاب گرامری ،مبهم است (يعني ،روشهای مختلفي برای تجزيه بعضي وروديها وجود دارد ، ) . اما اطلعات اضافي در تعريفها ،اين ابهام را دفع مي کند .بقیه کد ،برنامه های مستقلي است که در نیمه دوم فايل
hocyمي آيند :
محیط برنامه سازی لینوکس
250/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يك فرآيند دومرحله ای است :
leaves output in Y . tab.c Leaves executable Program in hoc 1
1
-0 hoc
$ yacc hoc.y $ ccy.
Tab. C $ hoc 1
0 . 0000007 1
syntax error near line
2/3 −3−4 hoc 1 :
تمرينت ) 1-8ساختار فايلت y.tab.cرا امتحان كنيدت ( .اين فايل حدودت 300خط برايت مي باشد ) .
$
hoc 1
محیط برنامه سازی لینوکس
252/322
ايجاد تغييرات منفي قبل از عبارت
قبلً ادعا كرديم كه استفاده ازت yaccايجاد تغيير در يك زبان را سهولت مي بخشدت .به عنوان مثال ،اجازه بدهيد علمت منفي را به hoc 1اضافه كنيم ،به گونه اي كه عباراتي نظير −3−4برآورد شوند و به عنوان خطاهاي تركيبي تلقي نشوند . دقیقا ً دو خط بايد به hoc.yاضافه شود .يك UNARY MINUS tokenجديد به آخر بخش ابتدايي اضافه مي شود تا اينکه به
علمت منفي بیشترين اولويت را بدهد .
به گرامر نیز يك محصول باری exprاضافه مي شود :
/ * new*/
΄% left ΄+΄ ΄- ΄%left ΄*΄ ΄ / %left UNARYMINUS
NUMBER {;}$ $ =-$1 : ΄ -΄ expr %prec UNARYMINUS }$$ =-$2;{1*new*1
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
$ cat makefile hoc 1 : hoc . 0 cchoc . 0−0 hoc 1 $
اين خطوط حاكي از آن است كه hoc 1به hocoوابسته است و hocoبا اجراي كامپايلر cc Cو قرار دادن خروجي در ، hoc 1به hoc 1تبديل مي شود make .از قبل مي داند كه چگونه فايل منبع yaccدر hoc.yرا به يك فايل شيمي ( hoc . 0 )abjectتبديل كند .
$ make
Make the first thing in makefile , hoc 1
Yacc hoc . Y CC – C Y.tab.C Rm Y.tab.c Mv y.tab.o hoc.o
Do it again
make realizes it΄s unnecessary
Cc hoc.o -0 hoc 1 $ make
΄ hoc 1 ΄ is up to date . $
) 82مرحله :2متغیرها و بازگشت از خطا ( )error recovery مرحله بعدت ( يك مرحله كوچكت ) افزودن حافظه بهت hoc 1تبراي ساختت hoc 2تاستت . حافظه 26متغير است كه از aتا zنامگذاري مي شوند .اين مرحله خيلي رسمي نيست اما يك مرحله مياني ساده و مفيد مي باشد .همچنين چند مورد بررسي خطا خواهيم افزود .اگر hoc 1را امتحان كنيد ،متوجه مي شويد كه برخورد آن با خطاهاي تركيبي چاپ كردنت تپيغامت توت تمتوقف تشدن تاست توت تاصلحت تخطاهاي تحسابي تمثلت تتقسيمت تبرت تصفحه امكانپذير مي باشد .
$ hoc 1 1/ 0
Floating $ exception – core dumped تغییراتي که برای اين موارد لزم است ساده بوده وحدود 35خط کد مي باشد تحلیل گر واژه ای ، yylexبايد حروف را به عنوان متغیرها شناسايي کند .گرامر بايد محصولتي به فرم زير را در بربگیرد:
يك عبارت مي تواند رابطه ای را شامل شود که چند جايگزيني همزمان نظیر X=Y=Z=0
VAR Var ΄ =΄ expr
expr:
محیط برنامه سازی لینوکس
254/322
را امکانپذير مي کند .
روش ساده تر جهت ذخيره مقادير متغيرها استفاده از يك آرايهت -26الماني استت .نام متغير تك حرفي مي تواند براي ايندكس گذاري آرايه استفاده شودت .اما اگر بنا باشد گرامر هم اسامي متغير و هم مقادير آنرا در يك پشته ذخيره كند ،بايستي به ya.ccگفته شود كه پشته آن شامل يك واحد دوگانه و يك intاست نه فقط يك واحد دوگانه .اين مورد تبات تيك تواحد تمعرفيت --------نزديك تسطح تبال تانجام تمي تگيردت .يكت define #يات تيك typedefبرايت تتنظيمت تپشتهت تبهت تيكت تنوعت تپايهت تايت تمثلت تنوعت تمضاعف تمناسب تاستت .اما مكانيسم واحد براي انواع واحد لزم است ،زيرات yaccدر عباراتي نظيرت $$=$ 2ت ت براي تعيين پايايي چك مي كند .در اين قسمت بخش گرامري hoc.yبراي hoc . 2آورده شده است :
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 83مرحله :3اسامي متغير دلخواه ،توابع داخلي
در اين نسخه ،نسخه ، hoc 3تعداد زيادي قابليت جديد و مقداري مرتبط با كد اضافي ، افزوده مي شود .ويژگي جديد اصلي دسترسي به توابع داخلي زير است :
محیط برنامه سازی لینوکس
257/322
sqrt int abs
logio
log
exp
dtam
Sin cos
يك اپراتور توان نيز اضافه كرده ايمت .اين اپراتور بالترين اولويت را دارد و ارتباط دهنده از راست استت .از آنجا كه تحليل گر واژه اي بايد بات اسهاي تداخلي بلندتر از يك كاراكتر مواجه تشود ت،ت تسعي تدر تجهت تافزايش تطول تاسامي تمتغيرها تكار تبيهوده تاي تنيستت . جداول عليم پيچيده تري براي ذخيره سازي مسير اين متغيرها خواهيم داشت .زماني كه اين جدول را داشته باشيم مي توانيم آنرا با نامها و مقاديري براي بعضي ارتباطات مفيد از پيش فراخواني كنيم .
نتیجه حاصل ،يك ماشین حساب مفید است :
رفتار را نيز تا حدي سازمانديه كرده ايم ت .در ، hoc 2رابطة x=exprنه تنها رابطه را ايجاد مي كند ،بلكه مقدار را هم چاپ مي كند زيرا همه عبارات چاپ مي شوند . $ hoc 2 x =2∗3.14159 6. 28318
Value printed for assignment to variable در ، hoc 3تمايزي بين رابطه ها و عبارات ساخته مي شود ،مقادير تنها براي عبارت چاپ مي شود . Assignment : no value is printed
$ hoc 3 x =2∗3.14159 x
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
تابع initکه با mainفراخواني مي شود ،نصب مي گردند .
داده ها به جای اينکه وارد کد شوند در جداول ذخیره مي شوند .زيرا فراخواني و ايجاد تغییر در جداول ساده تر است .از آنجا که
جداول تنها در اين فايل قابل مشاهده اند نه در کل برنامه ،جداول استاتیك نامیده مي شوند .بزودی به برنامه های مستقل رياضي
محیط برنامه سازی لینوکس sqrt,logبرمي گرديم .با ساخت در محل ،مي توان تغییراتي در گرامری که از اين توابع داخلي استفاده مي کند ،ايجاد کرد
261/322
محیط برنامه سازی لینوکس
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> .اسامي خطاهايي را که يافت مي
شوند را در برمي گیرد .
محیط برنامه سازی لینوکس
زماني که yaccرا روی گرامر جديد اجرا مي کنیم يك تشخیص غیرگرامری جالب رخ مي دهد:
264/322
$ 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را به منظور پيشگيري از نسبت دادن مقادير به ثوابت اصلح مي كنيد ؟ تمرين -6-8تابع داخلي a tan 2 y . x را كه زاويه اي را كه tanآن
y
x
است اضافه كنيد .
تابع داخلي () randرا كه يك متغير تصادفي اعشاري براساس توزيع يكنواخت روي فاصله (اوه) مي دهد را اضافه كنيدت .چگونه بايد گرامر را تغيير دهيد كه توابع داخلي با مقدار متفاوتي از آرگومانها اجازه عمل دهيد ؟
تمرين -7-8چگونه يك قابلیت به منظور اجرای دستورات hocمشابه با ويژگي ساير برنامه های UNIXاضافه مي کنید ؟
تمرين -8-8کد را در math.cتصحیح کنید بطوريکه از جدول به جای يکسری از توابع يکساني که تولید کرديم استفاده کند .
انحراف دیگري بر :make از آنجا كه برنامهت 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
فايلهای خروجي yaccو فايلهای صفر( )0را حذف مي کند .
$ make clean
اين مکانیسم تابعیتهای خالي در فايل makeنسبت به فايل پوسته ای به عنوان راهي برای نگهداری مقامي ارتباطات در يك تك فايل
ارجح است .در ضمن makeبه طراحي برنامه محدود نمي شود .اين مورد جهت بسته بندی هر سری از اپراتورها که تابعیتهای زماني دارند مناسب است .
انحرافي از 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مراجعه كنيد . 84مرحلة )4كامپايل به يك ماشين
Hoesرا كه مفسري براي يك زبان با جريان كنترل است ،در پيش داريم hoc 4 .يك مرحله مياني است كه توابعي مشابه hoc 3فراهم مي كند .با اين تفاوت كه با چارچوب مفسر hoesعمل مي كند .به اين دليل hoc 4را به اين گونه نوشته ايم كه دو برنامه يكسان رفتار كنند .اين مسأله براي اشكال زدايي با ارزش است .همانطوري كه ورودي تجزيه مي شود hoc 4 ،كدي را براي يك كامپيوتر ساده به جاي پاسخهاي محاسبه شده فوري ،توليد مي كند .هرگاه به آخر يك دستور مي رسد ،كد توليد شده تفسير مي شود تا نتيجه مطلوب را محاسبه كند .اين كامپيوتر ساده يك ماشين پشته است .زماني كه به يك كميت تحت عمل برخورد مي شود ،اين كميت به داخل يك پشته وارد ( )pushمي شودت ( .صحيحتر اين است كه بگوييم كدي براي راندن اين كميت به داخل پشته توليد مي شود )؛ بيشتر از اپراتورها روي مواردي كه در بالي پشته هستند عمل مي كنند .به عنوان مثال براي بررسي رابطة کد زير تولید میشود .
X=2*y
محیط برنامه سازی لینوکس
270/322
يك ثابت را به داخل پشته وارد کن
...ثابت 2
اشاره گر جدول علمت را به داخل پشته وارد کن برای متغیر y
برآورد :اشاره گر را با مقدار جايگزين کن
دو مورد بال را در هم ضرب کن ،نتیجه آنها را جايگزين کن اشاره گر جدول علمت را به داخل پشته وارد کن
...برای متغیر x
مقدار را در متغیر ذخیره کن ،اشاره گر را خارج کن
مقدار بال را از پشته پاك کن پايان دستورات
زماني که اين کد اجرا مي شود ،عبارت برآورد میشود و همانطور که در دستورات نشان داده شده ،نتیجه در 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آورده شده است :
هر المان روي پشته ،مفسر يا يك مقدار اعشاري و يا يك اشاره گر به يك ورودي جدول علمت استت .نوع داده هاي پشته يكي از اينهاستت .خود ماشين آرايه اي از اشاره گرهاست كه به برنامه هاي مستقلي نظير mulكه يك عمليات را انجام مي دهد و يا به داده ها در جدول علمت اشاره مي كندت .فايل سرآمدت hoc.hبايد به گونه اي افزايش يابد كه اين ساختارهاي داده اي و تعاريف تابعي را براي مفسر دربربگيرد .آنها در طول برنامه در جايي كه مورد نيازند شناخته مي شوند ( .ما تصميم گرفتيم كه تمام اين اطلعات را به جاي دو فايل در يك فايل قرار دهيم .در يك برنامه بزرگتر ،ممكن است بهتر باشد كه اطلعات سرآمد را به فايلهاي مختلفي تقسيم كنيم ،به گونه اي كه هر يك تنها در جايي كه مورد نيازند وارد شوند ) .
محیط برنامه سازی لینوکس
273/322
برنامه هاي مستقلي كه دستورات ماشين را اجرا و پشته را اداره مي كنند ،در فايل جديدي به نام code.cنگهداري مي شوند .از آنجا كه اين فايل حدود 150خط است ،آنرا در قطعات مختلف
مي آوريم :
محیط برنامه سازی لینوکس
274/322
ماشين در طي تجزيه با فراخوانيهايي به كد تابع ،توليد مي شود و به سادگي يك دستور را به موضع آزاد بعدي در آرايه progوارد مي كند .اين ماشين مكان دستوري (را كه در hoc 4استفاده نمي شود ) برمي گرداند .
اجرا كردن ماشين ساده است .به دليل كوچكي برنامه مستقلي كه ماشين را يكبار پس از نصب آن ،اجرا مي كند اجرا نسبتًا ساده است .
محیط برنامه سازی لینوکس
275/322
در هر سيكل شمارنده برنامه ( )PCبه دستور و دستور به تابع اشاره مي كند و آنرا اجرات تمي تكندت .بدينت تترتيبت PCافزايش تمي تيابدت تتات تاينكهت تآمادهت تدستورت تبعدي تشودت . دستوري ت تتباتتت opcode STOPرا ت تتخاتمه ت تتمي ت تتدهدتتت .بعضي ت تتاز ت تتدستورات ت ت،مثل pc,varpush,constpushرا افزايش مي دهند تا به آرلگانهايي كه دستور را دنبال مي كنند وارد شوند .
باقي ماشين ساده است .براي مثال ،عمليات حسابي در اصل مشابهند و با ويرايش يك تك نمونه توليد مي شوند .در اينجا addآورده شده است .
باي برنامه ها هم به همين ميزان ساده اند .
محیط برنامه سازی لینوکس
276/322
مشكل ترين بخش طراحي bltinاست كه بيان مي كند كه * pcبايد به صورت اشاره گره به تابعي كه يك مضاعف برمي گرداند و تابعي كه با d.valبه عنوان آرلگان اجرا مي شود ريخته شود . تشخيص ما در ، assign,evalدر صورتيكه همه چيز به درستي كار كند ،نبايد رخ دهد .خطاهاي برنامه اي را كه سبب مي شوند پشته ،بسته شود ،توضيح نداده ايم .اگر تغييري بدون دقت كافي ،در برنامه ايجاد كنيم ( كه امري معمول است ) ،بالسري در زمان و فضا در مقايسه با فايدة شناسايي خطا كوچك است .قابليت Cدر اداره اشاره گرها به توابع ،سبب ايجاد يكت كاد تكارآ و فشرده مي شودت .يك روش جايگزين براي ساخت اپراتورها ،ثوابت و تركيب توابع معنايي به يك دستور گزينه اي ( )switchبزرگ در
محیط برنامه سازی لینوکس
277/322
حين اجزا ،تفسير وجود دارد كه روش ساده اي است و به عنوان تمرين پيشنهاد مي شود . سومین انحراف از makeبه موازات توسعه كد منبع براي ، hocرديابي مكانيكي اينكه چه چيزي تغيير كرده و چه چيزي به آن بستگي دارد ،بيشتر و بيشتر با ارزش مي شود .زيبايي makeدر اين است كه آن دسته از كارهايي كه بدون دستيابي به آن مجبور بوديم دستي انجام دهيم (وگاهي اشتباه كنيمت ) يا با توليد يك فايل پوسته اي مخصوص انجام دهيم ،به صورت اتوماتيك انجام مي دهد . دو پيشرفت براي فايل makeساخته شده است .اولي بر اين مبناست كه اگرچه فايلهاي مختلف به ثوابت معرفي شده توسطت yaccدرت y.tab.hبستگي دارد ،اما هيچ نيازي به كامپايل مجدد آنها نيست مگر اينكه ثوابت تغيير كنندت :تغييرات كدت Cدرت hoc.y هيچ چيز ديگري را تحت تأثير قرار
نمي دهد .در فايل makeجديد ،فايلهاي صفر به يك
فايل جديد x.tab.hبستگي دارد كه تنها زماني كه ثوابت y.tab.hتغيير مي كنند ،جديد ( )updateمي شود .دومين پيشرفت ساختن قانون براي ( prچاپ فايلهاي مرجع) است كه به فايلهاي مرجع وابسته اند به طوريكه تنها تغييراتي كه در فايلها رخ داده چاپ شود . اولين تغييري كه ايجاد مي شود صرفه جويي در زمان در برنامه هاي بزرگتر ،زماني كه گرامر استاتيك است اما معناها استاتيك نيستند (موارد معمول ) ،است و دومين تغيير صرفه جويي در تعداد صفحات . در اينجا فايل makeجديد براي hoc 4آورده شده است :
محیط برنامه سازی لینوکس
278/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 روي نوع عمل استفاده كند .نسخه ها چگونه خطوط ،كد مرجع و سرعت اجرا را مقايسه مي كنند ؟ سادگي ،نگهداري و رشد را چگونه مقايسه مي كنند ؟ 8-5مرحله :5جریان کنترل و اپراتورهاي رابطه اي :اين نسخه ، hoc 5 ،نتيجه تلشي را كه در ساختن يك مفسر به خرج داده ايم به كار مي گيرد .اين نسخه عبارات while,y-elseرا شبيه آنچه در Cهست ،عبارات همگروه با { ، }andو يك عبارت چاپ فراهم مي كند .يك سري كامل از اپراتورهاي رابطه اي وارد شده اند )...,=,<,<( .در ضمن اپراتورهاي OR,ANDبه صورت ::: ، SSمي باشند ( .دو مورد آخر برآورد چپ به راست را كه در Cيك خصيصه است ،ضمانت نمي كنند ؛ آنها هر دو شرط را برآورد مي كنند حتي اگر لزم نباشد ). به گرامر نشانه هاي غيرپايانه اي و محصولت ، while , up , forبراكت و اپراتورهاي رابطه اي اضافه شده است .اين موارد سبب طولني تر شدن آن مي شوند ( .ممكن است wile, upطولني نكنند ) اما به پيچيدگي بيشتر برنامه نمي انجامند .
محیط برنامه سازی لینوکس
280/322
گرامر پنج مورد shift/reduceرا مشابه آنچه در hoc 3مطرح شد ،دارد . توجه كنيد كه اكنون دستوراتت stopدر مكانهاي مختلفي براي پايان دادن به تناوب توليد مي شوند .مانند قبل ،ت pragpمكان دستور بعد از توليد WiJIاست WiJI .زماني كه اين دستورات stopاجرا شوند ،حلقه در حال اجرا را خاتمه خواهد داد .با كمك يك ( subroutineزيرووالت ) كه از مكانهاي مختلفي فراخواني مي شود ،محصولي برايت end ايجاد مي شود .اين subroutineيك Stopتوليد مي كند و مكان دستوراتي كه آنرا دنبال مي كنند ،برمي گرداند . كدي كه براي while، upتوليد شده به مطالعه خاصي نياز دارد .زماني كه به لغت whileبرخورد مي شود ،عمليات whilecodeتوليد مي شود و موقعيت آن در ماشين به
محیط برنامه سازی لینوکس
281/322
عنوان مقدار محصول While:WHILE
برگردانده مي شود .همزمان ،دو موقعيت بعدي هم در ماشين ذخيره مي شوند تا بعداً تپرت شوندت .كدت توليدي بعدي عبارتي است كه تبخش شرطت whileرات مي تسازدت . مقداري كه توسط كد برمي گردد ،شروع كه براي شرط است .بعد از اينكه تمام دستور whileشناخته نشد ،دو موقعيت اضافي اي كه بعد از دستورت whileذخيره شده اند با مكانهاي بدنه حلقه و دستوري كه به دنبال حلقه مي آيد ،پر
مي شوند ( .كد آن
دستور بعدًا توليد مي شود ).
$1
مكانيت تدرت تماشينت تاستت تكه ت whileدرت تآنت تذخيرهت تميت تشودت .بنابراين
] $ 2[ 2 ] , $ 1[ 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
هنگام را مشابه آنچه در Cوجود دارد ،تضمين كنند. تمرينت )14-8يكت تعبارتت forمشابهت تآنچهت تدرت Cهستت تبهت hoesبيفزاييدت break .و Continueرا نيز اضافه كنيد . تمرين )15-8چگونه گرامر يا تحليل گر واژه اي ( يا هردو) hoesرا اصلح مي كنيد تا اينكه در مورد مكان خطوط جديد كمتر سخت گيري كند ؟ چگونه سمي كالن را به عنوان معادلي براي خطوط جديد اضافه مي كنيد ؟ چگونه يك تبديل دستوري اضافه مي كنيد ؟ چه تركيبي استفاده مي كنيد ؟ تمرينت )16-8يك تابزار تانقطاع تبهت hoesبيفزاييد تبه تطوريكه تمحاسبه تگريز( )runaway ل محاسبه شده اند را از دست بدهد ،متوقف شود . بدون اينكه حالت متغيرهايي كه قب ً تمرين )17-8لزوم توليد در يك برنامه ،اجراي آن و سپس ويرايش فايل در جهت ايجاد يك تغيير جزئي مشكل ساز استت .چگونهت hoesرا به گونه اي اصلح مي كنيد كه يك دستور ويرايشي فراهم كند كه شما را در يك ويرايشگر با كپي اي از برنامة hoeتان كه ل خوانده شده قرار دهد ؟ راهنمايي :يك opcodeمتني را در نظر بگيريد . قب ً 8-6مرحله :6توابع و عملكردها ،ورودي و خروجيمرحلهت تآخرت تتوسعهت ، hocت تحداقلت تدرت تاينت تكتابت ت،ت تافزايشت تقابليتت تجديدت ت،توابعت تو عملكردها ،
مي باشد .همچنين قابليت چاپ رشته هاي كاراكتري (علوه بر اعداد) و
خواندن مقادير از ورودي استاندارد را نيز افزوده ايم .همچنين hoc 6آرلگانهاي نام فايل را كه شامل نام ΄΄ ΄΄-براي ورودي استاندارد است قبول مي كند .اين تغييرات كلً 235خط به كد مي افزايد و كل برنامه را به 810خط مي رساند و اثري كه دارد اين است كه hocرا از يك ماشين حساب اوليه به يك زبان برنامه نويسي تبديل مي كند .همه خطوط برنامه را در اينجا نشان نمي دهيم .پيوست 3كل برنامه را در برمي گيرد به طوريكه مشاهده خواهيد كرد كه قطعات مختلف اين برنامه چگونه در تناسب با يكديگر قرار
گرفته اند .
در گرامر فراخوانيهاي تابعي عباراتند و فراخوانيهاي عملكردي دستور .جزئيات هر دو در پيوست 2توضيح داده مي شود .مثالهاي بيشتري نيز در اين پيوست آمده است .به عنوان مثل ،بيان و استفاده يك عملكرد براي چاپ تمام اعداد فيبوناتچي از آرلگانش به صورت زير است :
محیط برنامه سازی لینوکس
286/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مي كند .
زمانيكه يك تابع يا عملكرد در طي اجرا فراخواني مي شود تمام آرلگانها از قبل محاسبه شده و به داخل پشته وارد شده اند ( .اولين آرلگان داخلي ترين است ).پس از opcodeبراي فراخواني با اشاره گر جدول علمت و تعداد آرلگانها مي آيند .چارچوبي كه پشتهت تميت تشودت تتمامت تاطلعاتت تجالبت تراجعت تبهت تبرنامهت تمستقلت ترات تدرت تبرميت تگيرد.اين اطلعات شامل ورودي آن در جدول علمت ،جايي كه پس از فراخواني برمي گردد ، جايي كه آرلگانها روي پشته عبارت هستند و تعداد آرلگانهايي كه تابع را ت خوانده اند ، مي باشدت .چارچوب با فراخواني اي ايجاد شده است كه نهايتاً برنامه مستقل را اجرا مي كند .
اين ساختار در شكل 2-8آمده است . سرانجام برنامه فراخواني شده با اجزاي يك procretيا يك funcretباز خواهد گشت .
محیط برنامه سازی لینوکس
292/322
شكل )2-8ساختار داده ها براي فراخواني عملكرد
تابع retآرلگانها را از پشته خارج مي كند ،اشاره گر چارچوب fpرا مجدداً ذخيره مي كند و شمارنده برنامه را تنظيم مي كند .
محیط برنامه سازی لینوکس
293/322
برنامه هاي مفسر مختلف ،به كمترين جزئيات نياز دارند تا بتوانند در زماني كه در آن بازگشت در يك عمل تودرتو رخ مي دهد موقعيت را پيش ببرند .اين عمل ،خيلي رسمي نيست اما به طور مناسب با نشانه اي به نام بازگشت انجام مي گيرد كه زماني كه عبارت بازگشتي صحيح است ،ديده مي شود .اگر بازگشت تنظيم شود while code , ، if codeو اجراي زودهنگام خاتمه مي يابند call .آنرا به صفر برمي گرداند .
محیط برنامه سازی لینوکس
294/322
محیط برنامه سازی لینوکس
295/322
چاپ رشته ها و اعداد با prexpr,prstrانجام مي گيرد .
متغيرها يا تابعي به نام Varreadخوانده مي شوند .اگر end ---fileبرسد ،اين تابع صفر را برمي گرداند .در غير اينصورت
1
را برمي گرداند و متغير ويژه را تنظيم مي كند .
اگرت end – fileدر فايل هاي ورودي موجود رخ دهد moreinput,varreadرا مي خواند كه فايل آرلگان بعدي را در صورت وجود باز مي كند .ذكر آنچه ---moreinدر مورد فرآيند ورودي نشان مي دهد در اينجا مناسب بنظر نمي رسد .جزئيات تكامل در پيوست 3آمده است .اين بخش ما را به انتهاي طراحي hocمي رساند براي مقايسه در اينجا تعدادي خط غيرخالي در هر نسخه آورده شده است :
محیط برنامه سازی لینوکس
296/322
تعداد با برنامه ها محاسبه شده اند : زبان به هيچ وجه خاتمه نمي يابد ،حداقل هميشه فكر كردن به توسعه هاي مفيد ساده است ،اما ما در اينجا بيشتر از اين ادامه نمي دهيم .تمرينهاي بعدي ،بر بعضي مواردي كه با ارزش به نظر مي رسند تاكيد مي كنند . تمرينت hoc 6 )18-8را به گونه اي اصلح كنيد كه پارامترهاي رسمي نام گرفتند در subroutineها را به عنوان يك جايگزين $تبديل كند . تمرين )19-8همانطور كه بيان شد ،همه متغيرها به جز پارامترها كلي اند .بيشتر مكانيسم لزم براي افزودن متغيرهاي محلي روي پشته از قبل وجود داردت .يك رويكرد ،داشتن تعريف اتوماتيكي است كه فضايي روي پشته براي متغيرهاي ليست شده مي سازد .متغيرهايي كه اينگونه نامگذاري شوند كلي فرض مي شوند .در ضمن جدول wiu بايد توسعه يابد بگونه اي كه يك جستجو در ابتدا براي متغيرهاي محلي و سپس براي متغيرهاي كلي صورت گيرد .اين شيوه چگونه با آرلگانها برخورد
مي كند ؟
تمرين )20-8چگونه به hocآرايه مي افزائيد ؟ اين آرايه ها چگونه به توابع وعملكردها فرستاده مي شوند ؟ آنها چگونه باز مي گردند ؟ تمرين )21-8بررسي و اجراي رشته را توسعه دهيد ،به گونه اي كه متغيرها بتوانند رشته ها را به جاي اعداد نگه دارند .چه نوع اپراتورهايي مورد نيازند؟ بخش شكل اين عمل مديريت ذخيره سازي استت :اطمينان از اينكه رشته ها به گونه اي ذخيره مي شوند كه زماني كه مورد نياز نيستندآزاد شوند ،به گونه اي كه ذخيره مورد نياز خارج نشود .به عنوان يك مرحله مياني ،قابليتهاي بهتري براي فرمت خروجي اضافه كنيد ، نظير دستيابي به برخي فرمهاي عبارت printfدر . C )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
hoc 6 $ OBJS
CC $ CFLAGS $ OBJS −1 m −0 hoc 6
برنامه حاصله كد نيمرخ را در برخواهد گرفتت .زماني كه برنامه اجرا مي شود ، فايلي به نامت 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
فصل دهم آماده سازی مستندات يکي از کاربردهای سیستم UNIXويراستن و فرمت کردن فايل هاست .در واقع شرکت Belllabsکه با ضمانت سیستم آماده سازی فايل
سختافزار PDP-11را خريداری کند.خوشبختانه آنها بیش از آنچه انتظار ميرفت سود کردند.
اولین برنامه فرمت کننده roffنام داشت که بسیار کوچك بود و سريعو آسان نیز مورد استفادهرار ميگرفت .فرمت کننده بعدی که
nroffنام داشت توسط joeossannaپايه ريزی شد .که ازان پس بسیاری از برنامههای فرمت کننده زبان برنامهپذير nroffمورد استفاده قرار گرفت ،بهجای فراهم سازی هر سبك فايلي که توسط کاربر درخواست ميشد.
وقتي در سال 1973يك حروفچین کوچك حق نشر گرفتnroff ،برای استفاده از در سايزها وفونتها و کاراکترهای مختلفي ،که اين
حروفچین محیا ميکرد ،گسترش يافت .برنامه جديد troffنام گرفت nroff .و troffاساسا ً برنامههای مشابهي هستند و زبان ورودی مشابهي راميپذيرند .ما عمدتا ً در مورد troffبحث ميکنیم .اما بسیاری از نظريههای در مورد nroffنیزصدق ميکند که اين به علت
محدوديتهای دستگاههای خروجي است .يکي از مزيتهایtroffانعطاف پذيری زبان اصلي و برنامهپذير بودن آن استtroff .را
ميتوان وادار کرد کهبسیاری از برنامههای فرمت کننده را اجرا کند .اما انعطاف پذيری آن افزايش قیمتش را موجبميشود .استفاده از
troffکمي مشکل است ،و البته سختافزار آماده سازی فايل UNIXبرایپوشاندن بسیاری از قسمتهای آشکارل و عريان troffطرح ريزی شده است.
برای مثال يك صفحه بندی -سبك عمومي فايل و اينکه عنوان بندی و پاراگراف بندی چگونهاست .شماره صفحه کجای صفحه قرار گیرد بزرگي صفحه چقدر باشد و غیره از پیش ساختهنیست .بلکه بايد برنامه ريزی شود به جي اينکه کاربر را وادار کنیم تا اين
جزئیات را در فايلمشخص کند ميتوان يك بسته فرمان فرمت کننده استاندارد را برای اين کار فراهم ساخت.ديگر،اربر بسته بیان
نميکند که خط بعدی در وسط قرار گیرد با حروف بزرگ و فونت درشتبلکه ميگويد خط بعدی يك عنوان است .پس تعريف بسته بندی شده سبك عنوان مورداستفاده قرار ميگیرد .از اين پس کاربر مولفههای منطقي و اساسي يك فايل را بیان ميکند -نظیر عنوان
پارگراف پانوشت و غیره ...به جای سايز (اندازه) فونت و موقعیت.
متاسفانه ،چیزی که به عنوان يك بسته استاندارد فرمان فرمت کننده پیش ميرود برای مدتزمان زيادی ستاندارد باقي نميماند.
بستههای زيادی با کاربردهای وسیعي وجود دارد .ما دراينجا در مورد اهداف بستههای کلي صحبت ميکنیم .اولي msکه استاندارد اصلي ميباشد ودوميـ mmکه يك طرح جديديست که در سیستمـ vاستاندارد است .همچنین در مرود بسته manبرای صفحههای راهنما و چاپ کننده توضیح خواهیم داد.
ما بر روی msبیشتر تاکید ميکنیم .زيرا در thEditionmanاستاندارد است و نمونه است ازتمامي اينگونه بستهها و برای انجام کاری
به اندازه کافي قدرتمند است و ما برای تايپ اينکتاب از آن استفاده کردهايم ولي ميبايست آن را کمي بسط ميداديم .i .برای مثال با اضافهکردن يك فرمان برای به کار بستن واژههای in this fontدر متن.
اين نمونهای از يك تجربه است بستههای ماکروی بزرگ بسیاری از فرمانهای فرمت شدهکافیست البته گاهي اوقات بازگشت به فرمانهای اساسي troffضروريست و در اينجاقسمتهای کوچکي از troffرا توضیح خواهیم داد.
گرچه troffبه کلي توانايي کنترل فرمت خروجي را فراهم ميسازد .اما استفاده از اطلعاتپیچیدهای شبیه رياضیات جدولهای و ارقام
بسي مشکل است .هر يك از اين موارد به اندازهصفحه بندی سخت و دشوار است .حل چنین مشکلي اشکال متفاوتي را طلب ميکند.
به جایبستههای فرمانهای فرمت کننده زبان هايي با اهداف مشکلي برای رياضیات جدولها و ارقاموجود دارد که توضیح اينکه چه
محیط برنامه سازی لینوکس
303/322
چیزی خواسته شده است را آسان ميکند .هر گدام از اينها بايك برنامه مجزا استفاده ميشود که زبانش را به فرمان troffبر ميگرداند
ترجمه ميکند.برنامهها وتوسط مسیرهای اطلعاتي ( )pipesمنتقل ميشوند.
اين پیش پردازندهها نمونه خوبي از رهیافت UNIXبه عرصه کار است .نسبت به ساخت
troffحتي بزرگتر و پیچیدهتر از چیزی هست .برنامههای مجزا نیز با آن همکاری ميکنند(.البته ابزارهای توسعه زبان که در فصل 8 توضیح داده شده برای کمك به تحقیق سازی مورداستفاده قرار گرفته است).
ما دو برنامه را برايتان شرح خواهیم داد .اول tblکه جدولها را فرمت ميکند و دوم eqnکهعبارات رياضي را فرمت ميکند.
ما سعي ميکنیم در مورد آماده سازی فايلها و تامین ابزارها توصیه هايي داشته باشیم نمونههايي که در سراسر اين بخش بیان شد
فايلي ست که زبان nocو صفحات راهنمای nocراتوضیح خواهد داد .اين فايل در صفحه 2چاپ شده است.
19بستههاي ماكروي :ms يك فايل توسط ماژههای قسمتهای اصلي در بستههای ماکرو توضیح داده خواهد شد(.عنوان) سر بخشها ،پاراگرافها) و نه با جزئیاتي فاصله گذاری ،فونت و سايز در يك برنامه.اين روش شما را از انجام کاری سخت نجات ميبخشد و از فايل شما در برابر
جزئیاتنامربوطه محافظت ميکند .در حقیقت با استفاده از تعاريف مختلف دستگاه ماکرو -با اساميمنطقي مشابه -شما ميتوانید فايل
را با اندکي تفاوت جلوه گر سازيد .برای مثال يك فايلممکن است مراحل يك گزارش تکنیکي کنفرانس نشريه و يا کتاب را به وسیله فرمانهایفرمت کننده بگذارند ،که اين عملیات با چهار بسته ماکروی مختلف انجام ميشود .
ورود به 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
Author names one per line AB Abstraet,terminated by AE NH (Numbered neading caato matic numbering pp paragraph pp aNOTHE PARAGRAPH Sh (sub -heading )not numbered pp فرمانهای فرمت کننده بايد در ابتدا خط رخ دهد .ورودی بین فرمانها خالیست .محلقرارگیری سطرهای جديد در ورودی مهم نیست
زيرا troffکلمههای را از سطری به سطر ديگرانتقال ميدهد .تا سطرها را به میزان کافي طولني سازد( فرايندی که پر کردن () filling
نامدارد .و فاصله مناسب و يکنواختي بین واژهها ترتیب ميدهد تا حاشیهها را همتراز ميکند .اينتمرين خوبیست گرچه شروع کردن هر جمله در يك سطر جديد ويرايش بعدی را آسانترممکن ميسازد( .فرمان صفحه )292
فرمان Iنشانهاش را به صورت يك شناسه در troffنشان داده ميشود.
troff - ms - hoc .ms کاراکترها بعد از mبسته ماکرو را تعیین ميکنند .وقتي که توسطmsفرمت شده متن nocبه شکلزير ميباشد. HOCيك زبان محاورهای برای شناورشدن در کانون علم حساب.
Brian kernighan Rob pike چکیدهHOC :يك تقسیم کننده برنامهپذير ساده است برای فرو رفتن در عمق عبارات که دارای روندکنترل سبك C-تعريف کارکردها عملکردهای پیش ساخته عددی سینوس و الگاريتم است.
عباراتHOC :زبان عبارت است شباهت زيادی به Cدارد ،گرچه تعداد زيادی عبارت روند کنترل درآن وجود دارد بسیاری از عبارات مانند نسبت دهيها مورد بي توجهي قرار گرفته است.
نمايشگر: گرچه اينکه troffرفتن را پر کند و يا همستون سازد بسیار مطلوب است اما بعضي اوقات نیزناخوشايند به نظر ميرسد .برای مثال
برنامهها نبايد حاشیه خود را همستون سازند .يك چنینموارد فرمت نشده را متن نمايشگر ميخوانند .فرمانهایـ DE)display
End ( , DC)display start(msاز اينکه متن مطابق با ظاهرش چاپ شود جلوگیری ميکنند و آنم را بهصورت مرتب حاشیه بندی ميکند .در اينجا قسمت بعدی يك راهنمای nocنشان داده شدهکه شامل يك نمايشگر کوچك است.
(فرمان صفحه )293
محیط برنامه سازی لینوکس
305/322
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
جدول :9-1فرمانهای فرمت کننده ms
بستههاي ماكروي :MM ما در اينجا به جزئیات بستههای ماکرویـ 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اصلي : با يك بسته ماکروی خوب شما بايد مقداری از فرمانهایtroffرا بدانید برای کنترل فضای خالي ويا پر کردن و قرار دادن تب و غیره
فرمان brباعث يك انقطاع شکست ميشود که ورودی بعدی بههمراه .brبر روی خط خروجي جديد خواهد شد .که اين ميتوانست برای مثال برای دو قسمتيکردن عنوانهای بلند بر روی مکاني خاص استفاده شود.
فرمان nfپر کردن سطرهای خروجي را قطع ميکند .هر سطر ورودی مستقیم به سوی يك ازسیطرهي خروجي ميرود .فرمان fiپر کردن از عقب را قطع ميکند .فرمانceسطر بعدی را درمرکز قرار ميدهد.
فرمان bpيك صفحه جديد را آغاز ميکند .فرمان spباعث ميشود که تنها يك سطر خالي درخروجي ظاهر شود .يك فرمان spمي
تواند با يك نشانه همراه باشد تا مشخص کند چند سطرخالي و چند فضای خالي نیاز است.
sp 3 leave 3 blank lines sp 05 leave dank hal-line sp 1.5i leave 1.5 in sp 3p leave 3 points sp 3.1c leave 3.1 centimeters فضايي وسیع در انتهای صفحه ميشود .بنابراين .spبا bpبرابر ميکند.
فرمان taتب را در جايگاه هايش قرار ميدهد (که در هر اينچ ايتالیك شده است)
رمان بال جايگاههای تب را در فواصل معیني از حاشیه چپ مشخص ميکند با \
spهر شمارهای در هر اينچ قرار دارد اگر با همراه باشد جايگاه تب که توسط rافزوده شده متن رادر جايگاه تب بعدی همستون ميکند.
محیط برنامه سازی لینوکس
311/322
cيك تب مرکزی را تشکیل ميدهد فرمان
psاندازههای پونت را به nتنظیم ميکند و فرمان \ ،ft xفونت را به x.
قواعد در مرود سايزهای مفوی و بازگشت به میزان قبلي در \ f\sمشابه است. ماکروهای تعريف کننده:
ماکروهای تعريف کننده ما را بیشتر به سوی پیچیدگيهای troffمي برد .اما ما ميتوانیم بسیاری ازموارد اصلي را نشان دهیم .برای مثال در اينجا تعريفي از وجود دارد.
de cw sart a defin tion \&\f)cw\$\fp\\$2 font chang arund first argument End of definition وقتي که ماکرو راه اندازی ميشود \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وجوددارد.
(فرمان صفحه )303
که اين برنامه جدول زير را تشکیل ميدهد.
جدول -1اپراتورها ترتیب کاهش تقدم
( )**FORTRANبه توان رساني منفي سازی منطقي و حسابي
تقسیم ،ضرب تفريق ،جمع
بزرگتر يا مساوی ،بزرگتر ،اپراتور نسبي
کمتر يا مساوی ،کمتر
مساوی ،نامساوی منطقي( همه عملوندهايي که ارزيابي شدهاند)
منطقي و يا( همه عملوند هايي که
ارزيابي شدهاند)
نسبت دهي متناظر
کلماتي که قبل از سعي کالن ()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
اپراتورهايي موقعیتي مانند over,to,from,sup,sub
صورت بال اينگونه تفسیر ميشود.
اپراتورهايي شبیهـ 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
استفاده nroffاما mant-tصفحه حروفچین را که از troffاستفاده ميکند تولید ميکند.
نويسنده صفحات راهنما روی دايرکتری فرعي مناسب \usr\manيك فايل ميسازد .فرمانman، troffو يا nroffرا با يك بسته ماکرو برای چاپ صفحه فرا ميخواند.
فرمان صفحه 309نتیجه کار چنین است:
اختلف در سر و کار داشتن با گزينه هاستnroff :و troff
که آيا eqnو يا غیره اجرا ميشود يا نه .ماکروهای راهنما که با troff-manراه اندازی ميشوندفرمان troffرا که به سبك يك راهنما
فرمت شده است را تعريف ميکنند .آنها اساس" شبیهماکروهای msهستند .اما تفاوت هايي نیز وجود دارد به خصوص در قرار گرفتن
عنوان و درفرمانهای تغییر فونت ماکروهای مستند سازی ميشوند مختصراًـ درـ )man(1اما اساس آن بهراحتي در خاطر ميماند.
صفحه بندی صفحه راهنما به شکل زير است: (فرمان صفحه )309
اگر هر بخشي خالي باشد عنوان آن حذف ميشود .سطر THو بخشهای DES CRIPNAME,دارای احکام و دستوراتي هستند.
TH COMMAND SECTION-NUMBER سطر بال يك فرمان نامیده ميشود و شماره بخش را مشخص کند .سطرهای متنوع .SHقسمتهای صفحه راهنما را مشخص ميکند.
قسمت NAMEو SYNOPSISويژه و خاصهستند و بقیه شامل يك نثر معمولي هستند .قسمت (Comand,NAMEفرمان) خوانده ميشودو يك توصیف يك خطي از آن فراهم ميسازد .قسمتـ ( option,synopsisگزينه) خواهدهميشود که آنها را توضیح
نميدهد .چنانچه ـد ر ـهرـ قسمتي ـورودی ـخالي ـباشد ـتغییرات فونتميتواند توسطـ ـماکروهایـ B.I.Rمشخص ـشود .د ر ـقسمت synopsisنام و گزينه با حروفدرشت هستند .و بقیه اطلعات به صورت لتین است .قسمتهای synopsisو ed)1(NAMEبرای مثال اينگونه هستند.
به کاربرد نسبت به شکل ساده دقت کنید.
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شامل عبارات و بیاناتي ست .عبارات ارزيابي شده است و نتايج آن چاپ شدهعبارات به ويژه نسبت دهيها
عملکردها و يا توضیح روسشها تا زماني صريحاً چاپ نشودخروجي را تشکیل نميدهد.
:nocزبان واکنشي برای پونتهای شناور کننده حسابي توسط Rob pike,Briankerrighan
SEE Also
خطاها : بازسازی در میان عملکرد و توصیف روشها عملي است ناقص.
5-9ديگر ابزار آماده سازی فايل :برنامههای ديگری برای آماده سازی فايل وجود دارد .فرمانتوسط واژههای کلیدی به مرجع نگاه ميکند و دست آخر استنادهای خطي و قسمت مرجع را بهفايل شما نصب ميکند.
برای توصیف ماکروهای مناسب شما ميتوانید تربیتي دهید که referمرجعها را به همان سبكمورد نظر چاپ کند.
توضیحاتي برای تنوع ژورنالهای علمي کامپیوتر وجود دارد referقسمتي از است و برایبسیاری از طرحها انتخاب شده است.
بر روی تصاوير همان کاری را ميکند که معادلها انجام ميکدده تصاوير نسبت به معادلهها بسیراپیچیدهتر هستند حداقل در حد
حروفچیني و هیچج روش شفاهي چگونگي صحبت در مرودتصاوير وجود ندارد .بنابراين زبانها برای يادگیری و استفاده از آن
محیط برنامه سازی لینوکس
318/322
کارهايي انجام دادهاند در اينجا يك تصوير ساده و عبارات مربوط به آن در وجود دارد. تصويرهای اين کتاب همگي توسط pic,deapicانجام شده که جزئي از نميباشد اما قابلدسترسي هستند.
HOCيك زبان واکنشي برای شناور شدن پونتهای حسابي
Brian kerni ghan rob pike
چکیدهHOC :يك مفسر برنامهپذير ساده است که عبارات پونت را شناور ميکند که دارای روندکنترل به سبك cتعريف و عملکردها و عملکردهای پیش ساخته عددی عادی است مانندکوسینوس و لگاريتم.
- 1عباراتHOC :زبان عبارات است مانند که در ان چندين عبارت کنترل روند و بیاناتي شبیهنسبت دهي که عباراتي هستند که به
میزان آنها تنوجهتری شده است برای مثال اپراتور سینوسدهي میزان عملوند راستش را به عملوند چپش نسبت ميدهد و میزانش محصول و بهره ميدهد.گرامر عبارات اينچنین است:
number vaviable ()eapr enpr binop enpr unop enpr function اعداد پونت را شناور ميکند .فرمت ورودی که توسط تشخیص داده ميشود ارقام پونت دهياعداد توان علمت دار حداقل يك رقم
و يا يك پونت ده دهي وجود داشته باشد بقیه عاملهاگزينشي هستند.
اسامي متغیر فرمهای فرمت شدهای هستند که يك حرف توسط يك رديف حرف و يا رقم دنبالميشودbinop .به اپراتورهای ده دهي مانند مجموع و يا مقايسه منطقي رجوع ميکندunop .بهدو اپراتور منفي سازی رجوع ميکند .منفي سازی منطقي notو منفي سازی
حسابي تغییرعلمت جدول 1اپراتورها را لیست کرده است.
محیط برنامه سازی لینوکس
319/322
جدول :1اپراتورها
))**FORTRANبه توان رساني ^ منفي سازی حسابي و منطقي !
تقسیم ضرب *\ تفريق ،جمع -+
اپراتورهای نسبي بزرگتر و بزرگتر مساوی <<= کوچکتر و کوچکتر مساوی >>= مساوی .نامساوی==!=
منطقیو( همه عملوندها ارزيابي شدهاند)&&
منطقي يا همه عملوندها ارزيابي شدهاند
نسبت دهي متناظر=
عملکردها همان گونه که قبل ً توضیح داده شد ممکن است توسط کاربر تعريف شود نشانههایعملکرد عباراتي هستند که توسط کاما
( )،جدا ميشوند .تعداد زيادی عملکردهای از پیشساخته وجود دارد که همه آنها تنها دارای يك نشانهاند که در جدول 2توضیح داده شده است.
جدول 2عملکردهای از پیش ساخته
قدر مطلق
( xatan)xآرك تانژانت (xcos)xکوسینوس
(xeap)xبه توان رساني (xint)xقسمت صحیح
( log)xبر پايه xلگاريتم
(log10)xبر پايه x 10لگاريتم (xsin)xسینوس
(xsqrt)xراديکال عبارات منطقي دارای میزاني برابر 1/0صحیح و 0.0غلط است همچنین در cهر میزان صفحهی که برداشته ميشد صحیح بود. همچنین HOCدارای مقداری محتوای از پیش ساخته است که در جدول 3نشان داده شدهاست.
- 3عبارات و روند کنترل:
عبارات HOCيك گرامر دنبال کننده دارد:
محیط برنامه سازی لینوکس
320/322
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نیز در وجود داردبا اين تفاوت که انقطاع و يا دنباله
کلم در آن وجود ندارد.
3ورودي و خروجي :خواندن و چاپ كردن عملکرد ورودی خواندن مانند بقیه پیش ساختهها تنها يك نشانه بر ميگزينند .بر عکس بقیهپیش پردازندهها نشانهها يك عبارت نیستند بلکه نام متغیرهاست .شماره بعدی همانطور که دربال تعريف شده از ورودی استاندارد خوانده ميشود و به متغیرهای نام گذاری شده
نسبت دادهميشود .میزان بازگشت صحیح است اگر میزان آن خوانده شده باشد و غلط است اگر به پايانفايل و يا يك خطا مواجه شده باشد.
خروجي با عبارت تولید ميشود نشانههای کاما جدا شده در لیست عبارات و يك گیومه دو تاييمانند سطر جديد بايد فراهم شود آنهاهیچگونه به طور خودکار فراهنم نميشود.
محیط برنامه سازی لینوکس
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 :عملکرد فاکتوريل func fac()is ($1<=0)return 1 else return$ 1*fac($1-1)
نسبت به فاکتوريل به تقريب استرلینگ 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