ورودی و خروجی در اسکریپتهای Bash مبحث پیچیدهایست، زیرا انعطافپذیری بسیار زیادی در چگونگی انجام آن، وجود دارد. این فصل فقط یک ارائه سطحی از آنچه ممکن است، میباشد.
ورودی به هر اطلاعاتی که برنامه شما دریافت میکند(یا میخواند) اشاره مینماید. در یک اسکریپت Bash ورودی از چند محل مختلف میتواند برسد:
شناسههای خط فرمان(که در پارامترهای مکانی قرارگرفتهاند)
هر چیز دیگری که یک توصیفگر فایل میتواند به آن اشاره کند(لولهها،ترمینالها، سوکتها، و غیره). این موارد جلوتر بحث خواهند شد.
خروجی به هر اطلاعاتی که برنامه شما ارائه میکند(یا مینویسد) اشاره میکند. خروجی یک اسکریپت Bash نیز میتواند به چندین محل مختلف برود:
ورودی و خروجی، نان و پنیر اسکریپتنویسی پوسته هستند. معین کردن اینکه ورودی شما ازکجا میآید، چگونه به نظر میرسد، و شما برای بدست آوردن خروجی مطلوب خود، چه کاری باید روی آن انجام بدهید، هسته مرکزی احتیاجات تقریباً تمام اسکریپتها میباشند.
برای بسیاری از اسکریپتها، اولین(یا تنها) ورودی که به آن توجه مینماییم، شناسههایی میباشند که اسکریپت در خط فرمان دریافت نموده است. به طوری که در فصل پارامترها دیدیم، تعدادی پارامتر ویژه معتبر برای هر اسکریپت وجود دارد که، محتوی این شناسهها هستند. اینها پارامترهای مکانی نام دارند. این پارامترها یک آرایه خیلی ساده از رشتهها میباشند که با اعداد شاخصگذاری شدهاند(در حقیقت، در شل POSIX ، تنها آرایه موجود در شل هستند). به اولین پارامتر مکانی با
علاوه بر ارجاع یک به یک ، همچنین میتوانید به مجموعه کامل پارامترهای مکانی، با جایگزینی
یک روش دیگر کارکردن با پارامترهای مکانی، دور انداختن هر یک پس از استفاده است. یک دستور داخلی ویژهای به نام shift وجود دارد، که برای این منظور به کار میرود. موقعی که شما فرمان shift را صادر میکنید، اولین پارامتر مکانی (
در اسکریپتهای حقیقی، ترکیبی از این تکنیکها به کار میرود. یک حلقه برای پردازش
برای اختصار، در اینجا مثالهایی از پردازش شناسهها نمیآوریم. به جای آن، به FAQ جایی که مثالهای آنها قبلاً نوشته شده ارجاع میدهیم.
قبل از شروع به نوشتن، شناسایی کنید که ورودی برنامه شما از کجا میآید. اگر میخواهید اطلاعاتی را به اسکریپت خود ارسال کنید، روشی برای معنی کردن نوع اطلاعاتی که با آن سر و کار دارید، انتخاب نمایید. اگر احتیاج به ارسال نام فایلها دارید، ارسال آنها به صورت شناسهها، یک رویکرد عالی است، زیرا هر یک از آنها به صورت یک کلمه بستهبندی میگردد،.
چگونه میتوانم شناسههای( گزینههای ) خطفرمان را به آسانی مدیریت کنم؟
هر برنامهای اطلاعات، منابع، امتیازها و محدودیتهایی از پردازش والد خود به ارث میبرد. ( برای بحث پیشرفتهتر در این موضوع، بخش مدیریت پردازش را ملاحظه کنید.)یکی از آن منابع، مجموعهای از متغیرها به نام متغیرهای محیط میباشند.
در Bash, متغیرهای محیط تا اندازه بسیار زیادی مشابه متغیرهای معمولی مورد استفاده ما، کار میکنند. تنها تفاوت واقعی، آن است که آنها قبلاً، موقعی که اسکریپت شروع به اجرا میکند، مقرر شدهاند، ما خودمان نباید به آنها مقداردهی کنیم.
به طور سنتی، متغیرهای محیط نامهایی تماماً با حروف بزرگ دارند، از قبیل
ارسال اطلاعات به برنامهها از طریق متغیرهای محیط، در بسیاری موقعیتها سودمند است. یکی از آنها اولویتهای کاربر است. در سیستمهای یونیکسی، همه کاربران علایق و بیعلاقگیهای یکسان در برنامههای کاربردی ندارند، و در برخی موارد، ممکن است همه به یک زبان صحبت نکنند. بنابراین، برای کاربران سودمند خواهد بود که به هر برنامه بگویند کدام ویرایشگر مورد علاقه آنها برای اجرا میباشد(متغیر محیطی
متغیرهای محیط همچنین میتوانند به طور بینهایت آسانی در حین کار تنظیم گردند( آسانتر از آنکه اگر همان اطلاعات در یک فایل ذخیره شده باشند). موقعی که در Bash دستوری را اجرا میکنید، گزینهای دارید، برای تعیین یک تغییر موقتی محیط که فقط در طول مدت اجرای آن فرمان مؤثر است. این با قرار دادن عبارت
$ ls/ tpm ls: no se puede acceder a /tpm: No existe el fichero o el directorio $LANG = C ls/ tpm ls: cannot access /tpm: No such file or directory
محیط موقتی
اگر میدانید که برخی اطلاعات در یک متغیر محیط ذخیره شده است، در اسکریپت، میتوانید درست مانند سایر متغیرها از آن استفاده کنید:
if [[ $ DISPLAY ]] xterm; then-e top else topfi
این مثال، در صورتی که متغیر محیطی
اگر میخواهید اطلاعاتی را در متغیر محیطی قرار دهید که به پردازشهای فرزند به ارث برسد، فرمان export را به کار ببرید:
exportMYVAR = something
بخش دشوار مطلب در اینجا آنست که تغییرات محیط شما فقط برای فرزندان موروثی خواهد بود. نمیتوانید محیط یک برنامه را که از قبل در حال اجراست، یا شما آن را شروع نکردهاید، تغییر دهید.
تغییر محیط و سپس اجرا، برای برخی برنامهها به شدت رایج میباشد. اسکریپتی که این کار را به عنوان وظیفه اصلیاش انجام میدهد یک WrapperScript مینامند.
در اسکریپتهای خود از نامهای تماماً با حروف بزرگ برای متغیرها استفاده نکنید. برای پرهیز از تصادمات، حروف کوچک یا ترکیبی از کوچک و بزرگ به کار ببرید .
من سعی میکنم اسکریپتی بنویسم که دایرکتوری جاری را تغییر دهد( یا یک متغیر را تنظیم کند)، اما بعد از به پایان رسیدن اسکریپت، در همان جایی هستم که از آنجا شروع کرده بودم(یا متغیر من موجود نیست)!
توصیفگرهای فایل (به طور کوتاه: FDها) روشی برای ارجاع برنامهها به فایلها، یا منابع دیگری که همانند فایلها کارمیکنند( از قبیل لولهها،دستگاهها، سوکتها، یا ترمینالها ) میباشند. FDها نوع مشابه اشارهگرها به منابع داده، یا محلهایی که اطلاعات میتوانند نوشته شوند، هستند. موقعی که چیزی از آن FD, خوانده یا در آن نوشته میشود، داده در حال نوشته شدن در منبع FD یا خوانده شدن از آن میباشد.
به طور پیشفرض، هر فرایند جدیدی با سه FD آغاز میشود. به این توصیفگرهای فایل با نامهای ورودی استاندارد، خروجی استاندارد و خطای استاندارد رجوع میشود.در حالت کوتاه شده به ترتیب
اجازه بدهید کمی این تعاریف را محسوستر کنیم. در اینجا یک نمایش تجربی از چگونگی کار ورودی استاندارد و خروجی استاندارد میآوریم:
$ read-p "What is your name? "name ; echo "Good day,$ name. Would you like some tea?"What is your name? lhunath Good day, lhunath. Would you like some tea?
read دستوری است که اطلاعات را از
پس
$ rmsecrets rm: cannot remove `secrets': No such file or directory
بدون داشتن فایلی به نام
به خاطر داشته باشید موقعی که اسکریپتها را ایجاد میکنید،شما باید پیغام خطاهای سفارشی خود را به توصیفگر
echo "Uh oh. Something went really bad..">& 2
توصیفگر فایل: یک شاخص عددی ارجاع به یکی از فرآیندهای فایل باز است. هر دستوری حداقل سه توصیفگر اصلی دارد: FD شماره 0،
اساسی ترین شکل دستکاری ورودی و خروجی در BASH تغییر مسیر است. تغییر مسیر برای تغییر منبع داده یا مقصد توصیفگرهای فایل یک برنامه کاربردی به کار میرود. به طریقی، که میتوانیدخروجی برنامه را به جای ترمینال به یک فایل ارسال کنید، یا برنامهای داشته باشید که به جای خواندن از صفحه کلید از یک فایل بخواند.
همچنین، تغییر مسیر به اشکال مختلف میباشد. که عبارتند از تغییر مسیر فایل، دستکاری توصیفگرفایل، Heredocها و Herestringها.
در مستندات گنو: Redirections
تغییر مسیر: شیوه تغییر یک توصیفگرفایل معین برای خواندن وردیاش از جای دیگر یا ارسال خروجیاش به جایی دیگر میباشد
تغییر مسیر فایل تغییر یک توصیفگر فایل منفرد برای اشاره به یک فایل را شامل میگردد. بیایید با یک تغییر مسیر خروجی شروع کنیم:
$ echo "It was a dark and stormy night. Too dark to write."> story $ catstory It was a dark and stormy night. Too dark to write.
عملگر
در نتیجه، فرمان echo خروجیاش را به ترمینال ارسال نمیکند، به جای آن، تغییر مسیر
بایستی توجه گردد که این تغییر مسیر فقط برای دستور منفرد echo که برایش به کار برده شده، مؤثر است . دستورات دیگری که بعد اجرا میشوند، ارسال خروجی خود به محل
سپس ما از برنامه cat برای چاپ محتویات آن فایل استفاده کردیم. cat برنامه کاربردی است که محتویات تمام فایلهایی که به عنوان شناسه به آن دادهایم را میخواند. سپس هر فایل را یکی پس از دیگری به
هشدار:مثالهای بسیار زیادی از کد ها و خودآموزهای شل در اینترنت به شما میگویند، هر جا احتیاج به خواندن محتویات یک فایل دارید از cat استفاده کنید. این کار ضرورت ندارد! cat در الحاق چند فایل به یکدیگر خوب خدمت میکند، یا به عنوان یک ابزار سریع در اعلان شل برای دیدن آنچه داخل یک فایل است. شما نباید از cat در اسکریپتهای خود برای لولهکشی فایلها به دستورات، استفاده کنید. تقریباً همیشه راههای بهتری برای انجام این کار وجود دارد. لطفاً این هشدار را به خاطر بسپارید. استفاده بیمورد از cat صرفاً به ایجاد یک پردازش اضافی منجر خواهد شد، و غالباً سرعت خواندن ضعیفتری را نتیجه میدهد، زیرا cat نمیتواند مفهوم آنچه میخواند و هدفی که داده، برای آن خوانده میشود را تشخیص دهد.
موقعی که ما برنامه cat را بدون هرگونه شناسهای به کار میبریم، به طور آشکاری نمیداند که کدام فایل را بخواند. در این وضعیت، cat به جای خواندن از یک فایل، فقط از
$ cat
حتی اعلان فرمان را به شما باز نمیگرداند! چه اتفاقی رخ میدهد؟ cat هنوز در حال خواندن از
$ cattest? test?
حالا چرا test? را دو مرتبه نمایش میدهد؟ خوب، همانطور که شما تایپ میکنید، ترمینال شما تمام کاراکترهایی را که به
بیایید یک تغییر مسیر ورودی را برای پیوست یک فایل به
$ cat< story The story of William Tell. It was a cold december night. Too cold to write.
نتیجه این دقیقاً همانند نتیجه cat
عملگرهای تغییر مسیر میتوانند با تقدم یک عدد همراه گردند. آن عدد توصیفگرفایلی که تغییر میکند را مشخص مینماید.
اجازه دهید با چند مثال خلاصه کنیم:
command
command 1
command
command
عدد مربوط به FD(توصیفگرفایل)
$for homedir in /home/* >do rm "$ homedir /secret " >done 2> errors
در این مثال، روی هر دایرکتوری(یا فایل) در شاخه /home حلقه ایجاد میکنیم. سپس ما سعی در حذف فایل
ممکن است توجه نموده باشید که عملگرتغییر مسیر روی فرمان rm نمیباشد، بلکه روی
اجازه بدهید ببینیم نتیجه حلقه ما چه بوده:
$ caterrors rm: cannot remove `/home/axxo/secret': No such file or directory rm: cannot remove `/home/lhunath/secret': No such file or directory
دو پیغام خطا در فایل ثبت خطا. دو نفر که فایل
اگر یک اسکریپت مینویسید، و پیشبینی میکنید که یک دستور معین تحت شرایطی ممکن است ناموفق باشد، اما نمیخواهید کاربر اسکریپت، با خطاهایی که ممکن است دستور ایجاد کند پریشان گردد، میتوانید FD آن را ساکت کنید. ساکت کردن آن به آسانی یک تغییر مسیر فایل معمولی است. فقط تمام خروجی برای آن FD را به سیاهچاله سیستم ارسال میکنیم:
$for homedir in /home/* >do rm "$ homedir /secret " >done 2 > /dev/null
فایل /dev/null همیشه خالی است، مسئلهای نیست که در آن چه مینویسید یا از آن میخوانید. همینطور، موقعی که ما پیغام خطاها را در آن مینویسیم، آنها ناپدید میشوند. فایل /dev/null همچنان مانند قبل خالی میماند. چنین است زیرا یک فایل معمولی نمیباشد، یک دستگاه مجازی است. بعضیها /dev/null را bit bucketزیرنویس مترجم 1 مینامند.
یک مطلب نهایی هست که باید در باره تغییر مسیر فایل بدانید. جالب است که شما میتوانید یک فایل ثبت وقایع برای نگهداری پیغامهای خطایتان ایجاد کنید، اما همانطور که قبلاً اشاره کردم، BASH موقعی که به یک فایل تغییر مسیر داده میشود، محتویات موجود آن فایل را ازبین میبرد. در نتیجه، هر دفعه که ما آن حلقه را برای حذف کردن فایلهای secret اجرا کنیم، فایل ثبت وقایع ماقبل از اینکه دوباره با پیغامهای جدید پر شود،از سر کوتاه و خالی میشود. چه کار باید بکنیم، اگر میخواهیم رکوردی از هر پیغام خطای تولید شده در حلقه را حفظ کنیم؟ چه کار کنیم که با هر بار اجرای حلقهزیرنویس مترجم 2 فایل از سر کوتاه نشود؟ چاره کار با دوگانه کردن عملگر تغییر مسیر به دست میآید.
$for homedir in /home/* >do rm "$ homedir /secret" >done 2 >> errors
!Hooray
درضمن، فاصله بین عملگر تغییر مسیر و نام فایل، اختیاری است. بعضی افراد مینویسند
تکرار مفید:
وقتی که یک برنامه به فایل دادهای نیاز دارد، و برای خواندن داده از
موقعی که برنامه ای طراحی مینمایید که میتواند دادهها را از منابع مختلفی تغذیه کند، واقعاً اغلب بهترین راه آنست که برنامه شما از
در مستندات گنو: Redirecting Input, Redirecting Output, Appending Redirected Output, Redirecting Standard Output and Standard Error
حال که دانستید چگونه پردازش ورودی و خروجی را با فرستادن به فایلها یا دریافت از آنها اداره کنید، اجازه دهید باز هم کمی آن را جذابتر نماییم.
همانطور که میدانید، تغییر منبع یا مقصد توصیفگرهایفایل برای اشاره به فایلها یا از آنها، امکان پذیر است. همچنین کپی کردن یک FD به دیگری ممکن است. اجازه دهید بستر آزمایش سادهای فراهم کنیم:
$ echo "I am a proud sentence."> file
فایلی به نام
برنامه کاربردی به نام grep وجود دارد که به طور مختصر در فصل قبل دیدهایم. grep شبیه یک نوار لولهای است: میتوانید تقریباً در هر پروژهای آن را به کار ببرید(خواه ایده خوبی باشد یا نباشد). اساساً یک الگوی جستجو را به عنوان یک شناسه دریافت میکند و میتواند چند نام فایل نیز به عنوان شناسه اضافی دریافت نماید. درست مانند cat، برنامه grep نیز اگر نام فایلی را به عنوان شناسه تعیین نکنید از
$ ls house/drawer closet dustbin sofa $ grep-r socks house/house/sofa:socks
در این مثال تخیلی، دایرکتوری به نام house با چند قطعه اثاثیه منزل در آن به عنوان فایل داریم. اگر ما در جستجوی socks(ساکها)ی خود در هر یک از آن فایلها باشیم، grep را به جستجو در دایرکتوری house/ میفرستیم. grep هر چیزی در آنجا را جستجو میکند، هر فایل را باز میکند و محتویات آن را نگاه میکند. در مثال ما، grep ساکها( socks) را در فایل house/sofa پیدا میکند،احتمالاً پنهان شده زیر یک بالش. مثال واقعبینانهتری میخواهید؟ حتماً:
$ grep "$ HOSTNAME " /etc/*/etc/hosts:127.0.0.1 localhost Lyndir
اینجا به grep دستور دادهایم هر آنچه
خوب، حال که grep را دریافتید, اجازه بدهید با دستکاری توصیفگرفایل ادامه دهیم. به خاطر میآورید که فایلی به نام
$ grep proud *file:I am a proud sentence.
صحیح! grep جمله ما را در
$ grep proud file 'not a file'file:I am a proud sentence. grep: not a file: No such file or directory
این دفعه، به grep دستور دادهایم رشته proud را درفایلهای '
حال، چطور میتوان این جمله grep را به طور کامل خاموش کنیم؟ میتوانیم تمام خروجی که روی ترمینال ظاهر میشود را به جای آن به یک فایل بفرستیم، اجازه بدهید آن را
# Not quite right.... $ grep proud file 'not a file'> proud.log 2 > proud.log
صحیح به نظر میآید؟ ابتدا از
$ echo "I am a very proud sentence with a lot of words in it, all for you."> file2 $ grep proud file2 'not a file'> proud.log 2 > proud.log $ catproud.log grep: not a file: No such file or directory of words in it, all for you.
در اینجا چه اتفاقی رخ داده؟ grep اول فایل
لازم است از داشتن دو توصیفگرفایل مستقل از یکدیگر که روی یک منبع یا مقصد کار کنند، پیشگیری نماییم. میتوانیم با دونسخهای نمودن توصیفگرفایل، این کار را انجام دهیم:
$ grep proud file 'not a file'> proud.log 2 >& 1
برای درک این مطالب لازم است توجه داشته باشید که: تغییر مسیر فایل از چپ به راست خوانده میشود.این ترتیبی است که BASH آنها را پردازش میکند. اول،
یک FD دونسخهای با دو FD مستقل از یکدیگر که به یک محل اشاره میکنند، متفاوت عمل مینماید. عملیات نوشتن در هر دونسخه دقیقاً همانند است. آشفتگی مربوط به یک FD اشاره کننده به ابتدای فایل در حالیکه دیگری قبلاً آن را ادامه داده وجود نخواهد داشت.
مراقب باشید ترتیب آنها را اشتباه نکنید:
$ grep proud file 'not a file'2 >& 1 > proud.log
این مثال
$ grep proud file 'not a file'&> proud.log
این نیز همان
در مستندات گنو: Duplicating File Descriptors, Moving File Descriptors, Opening File Descriptors for Reading and Writing
در پرسش و پاسخهای رایج:
چطور میتوانم چند دستور را در یک مرحله تغییر مسیر بدهم؟
چطور میتوانم خروجی 'time' را به یک متغیر یا فایل تغییر مسیر بدهم؟
چگونه میتوانم از dialog برای دریافت ورودی کاربر استفاده کنم؟
گاهی نگهداری دادهها در یک فایل زائد است. ممکن است فقط مقدار بسیارکمی داشته باشیم -- مناسب برای به راحتی گنجاندن آن در خود اسکریپت .یا ممکن است خواسته باشیم محتوای متغیری را ، بدون آنکه اول آن را در یک فایل بنویسیم، به یک دستور تغییر مسیر بدهیم.
$ grep proud<< END > I am a proud sentence. >END I am a proud sentence.
این یک Heredoc (یا سند اینجا) میباشد. وقتی میخواهید یک قطعه کوچک چند سطری دادهها را در اسکریپت خود تعبیه کنید Heredocها سودمند هستند. (تعبیه قطعات بزرگ تکنیک نامناسبی است. شما باید منطق خود(کد خودتان) و ورودی خود(دادههایتان) را جداگانه و ترجیحاً در فایلهای مختلف نگاه دارید، مگر اینکه دادهها جزئی باشند.)
در یک Heredoc، کلمهای برای ایفای نقش نگهبان انتخاب میکنیم. هر کلمهای میتواند باشد، ما از
چند مورد متمایز برای Heredocها وجود دارد. به طور معمول، نمیتوانید آنها را دندانهدار کنید، همه فاصلههایی که در اینجا برای دندانهدار کردن اسکریپت به کار ببرید در
echo "Let's test abc:"if [[ abc = a * ]]; then cat<< END abc seems to start with an a!END fi
چنین نتیجه خواهد داد:
Let's test abc: abc seems to start with an a!
میتوانید با حذف موقتی توگذاری برای سطرهای Heredocهای خود، از این مطلب اجتناب کنید. به هر حال، موجب بدشکل شدن تورفتگی شکیل و زیبای شما میگردد. یک جایگزین وجود دارد. اگر از
به طور پیشفرض، جایگزینیهای BASH در محتوای Heredoc انجام میشود. هر چند، اگر کلمهای که برای جداکردن Heredoc خود به کار میبرید را نقلقولی نمایید، BASH هیچگونه جایگزینی در محتویات انجام نخواهد داد. برای دیدن تفاوت، این مثال را با و بدون کاراکترهای نقلقول امتحان کنید:
$ cat<<' XYZ ' > My home directory is$ HOME >XYZ My home directory is $HOME
رایجترین کاربرد Heredocها، در ارائه مستندات به کاربر است:
usage() { cat<< EOF usage: foobar [-x] [-v] [-z] [file ...] A short explanation of the operation goes here. It might be a few lines long, but shouldn't be excessive.EOF }
حالا اجازه بدهید Herestring خیلی مشابه اما فشردهتر را آزمایش کنیم:
$ grepproud <<< "I am a proud sentence"I am a proud sentence.
ایندفعه،
$ grepproud <<< "$USER sits proudly on his throne in$ HOSTNAME ."lhunath sits proudly on his throne in Lyndir.
Herestringها کوتاهتر، کمتر مزاحم، و به طور کلی مناسبتر از Heredocهای حجیم همتای خود میباشند. گرچه آنها قابل حمل به پوسته Bourne نیستند.
بعداً، شما در باره لولهها و اینکه چطور میتوانند برای ارسال خروجی یک دستور به
$ echo 'Wrap this silly sentence.'| fmt -t -w 20Wrap this silly sentence. $ fmt-t -w 20<<< 'Wrap this silly sentence.'Wrap this silly sentence.
heredocهای بلند به طور معمول ایده نامناسبی هستند، زیرا اسکریپتها باید محتوی منطق باشند، نه دادهها. اگر اسکریپت به سند حجیمی نیاز دارد، باید آن را در یک فایل جداگانه با اسکریپت همراه کنید. با این وجود Herestringها، اغلب کاملاً سودمند هستند بویژه برای ارسال محتوای یک متغیر(به جای فایلها) به فیلترهایی مانند grep یا sed.
در مستندات گنو: Here Documents, Here Strings
حال که میتوانید بدون دردسر توصیفگرهای فایل را برای هدایت انواع معینی از خروجیها به فایلهای معین، مدیریت نمایید، وقت آنست که رموز مبتکرانهتری که برای تغییرمسیر ورودی و خروجی در دسترس میباشد را بیاموزید.
میتوانید از تغییرمسیرفایل برای نوشتن خروجی در فایلها یا خواندن ورودی از فایلها، استفاده کنید. اما اگر بخواهید خروجی یک برنامه را به طور مستقیم به ورودی برنامه دیگر مربوط کنید چطور؟ از آن طریق میتوانید زنجیر پیوستهای از پردازش خروجی ایجاد کنید. اگر از قبل درباره
$ ls $ mkfifomyfifo ; lsmyfifo $ grepbea myfifo & [1] 32635 $ echo "rat > cow > deer > bear > snake"> myfifo bear
از دستور mkfifo برای ایجاد یک فایل جدید به نام 'myfifo' در دایرکتوری جاری استفاده کردیم. این یک فایل معمولی نیست، بلکه یک
در مثال ما،
اما این فایلهای موقتی یک اذیت واقعی هستند. شاید شما مجوز نوشتن نداشتهباشید. لازم است به خاطر داشته باشید که فایلهای موقتی که ایجاد نمودهاید را پاک کنید. لازم است مطمئن شوید که دادهها وارد و خارج میشوند، یا شاید
به خاطر این مسائل، ویژگی دیگری در دسترس قرارگرفته است: لولهها. در اصل، لوله فقط
$ echo "rat > cow > deer > bear > snake"| grepbea bear
لوله با استفاده از عملگر
لولهها به طور وسیعی به عنوان پسپردازش خروجی برنامهها به کار میروند. به
عملگر لوله برای هر دستور یک محیط پوسته فرعی ایجاد میکند. آگاهی از این مطلب اهمیت دارد، به علت آنکه، هر متغیری که در دستور دوم تعیین یا ویرایش کنید، در خارج از آن به صورت ویرایش نشده قبلی ظاهر میگردد. اجازه بدهید تشریح نمایم:
$message = Test $ echo 'Salut, le monde!'| readmessage $ echo "The message is:$ message "The message is: Test $ echo 'Salut, le monde!'| { readmessage ; echo "The message is: $message";} The message is: Salut, le monde! $ echo "The message is:$ message "The message is: Test
وقتی خط لوله به پایان میرسد، پوستههای فرعی که برای آن ایجاد شدهاند نیز خاتمه مییابند. همراه با پوستههای فرعی، هر تغییر و تبدیل انجام شده در آنها نیز از بین میرود. بنابراین مراقب باشید!
تکرار مفید:
لولهها به عنوان پسپردازشگر خروجی برنامهها، خیلی جالب هستند. به هرحال، شما بایدمراقب باشید در کاربرد آنها زیادهروی نکنید. اگر شما خطلولهای که شامل سه برنامه یا بیشتر باشد را به انتها برسانید، وقت آنست که از خود بپرسید آیا در حال انجام امور به روش هوشمندانهای هستید؟ امکان دارد قادر باشید ویژگیهای بیشتری از برنامه را نسبت به آنچه در یک پسپردازش در لوله به کار گرفتهاید، استفاده کنید. هر دستور جدید در یک خطلوله موجب یک پوسته فرعی جدید میگردد و یک برنامه جدید باید بارگزاری شود. همچنین این مطلب دنبال کردن منطق اسکریپت شما را دشوار میسازد!
من متغیرهایی را در یک حلقه مقرر میکنم. چرا آنها پس از اتمام حلقه، ناگهان ناپدید میگردند؟ یا، چرا نمیتوانم دادهها را برای خواندن لولهکشی نمایم؟
چطور میتوان دو پردازش را با استفاده از لولههای بانام (fifoها)به یکدیگر ارتباط داد؟
در کنار عملگرهای ورودی و خروجی استاندارد، bash همچنین چند عملگر پیشرفتهتر نیز که کار با پوسته را دلپسندتر مینمایند، فراهم نموده است.
پسرعموی لوله، عملگر جایگزینی پردازش است، که به دو شکل ظاهر میگردد:
کاری که انجام میدهد، اساساً اجرای دستور داخل پرانتزها میباشد. با عملگر
در اینجا چگونگی انجام آن را در عمل میبینیم: موقعیتی را در نظر بگیرید که میخواهید تفاوت میان خروجی دو دستور را ببینید. به طور معمول، باید دو خروجی را در دو فایل قرار بدهید و با برنامه diff آنها را مقایسه کنید:
$ head-n 1 .dictionary > file1 $ tail-n 1 .dictionary > file2 $ diff-y file1 file2Aachen | zymurgy $ rm file1 file2
میتوانیم با به کاربردن عملگر جایگزینی پردازش، تمام آن را در یک سطر انجام بدهیم، و نیازی به پاکسازی دستی هم نیست:
$ diff-y <( head-n 1 .dictionary ) <( tail-n 1 .dictionary ) Aachen | zymurgy
قسمت
$ diff-y /dev/fd/63 /dev/fd/62
در اینجا میبینیم که وقتی ما از جایگزینی پردازش استفاده میکنیم، bash چگونه diff را اجرا میکند. دستورهای head و tail را اجرا میکند، خروجیهای آنها را به ترتیب به فایلهای /dev/fd/63 و /dev/fd/62 تغییرمسیر میدهد. سپس فرمان diff را با قبول کردن آن نام فایلها در جایی که ما عملگرهای جایگزینی پردازش را قرار داده بودیم اجرا میکند.
پیادهسازی واقعی فایلهای موقتی ازیک سیستم تا سیستم دیگر فرق میکند. در حقیقت، با قرار دادن یک دستور echo در ابتدای دستور یک سطری خود، میتوانید به طور واقعی مشاهده کنید آنچه در بالا گفته شد، به نظر دستور diff خواهد آمد:
$echo diff -y <( head-n 1 .dictionary ) <( tail-n 1 .dictionary ) diff -y /dev/fd/63 /dev/fd/62
عملگر
$ tar-cf >( ssh host tarxf - ) .
جایگزینی پردازش روش فشردهای برای ایجاد خودکار فایلهای موقتی FIFO در اختیار قرار میدهد. آنها نسبت به زمانی که شما خودتان به طور دستی pipeهای با نام را ایجاد میکنید، کمتر انعطافپذیر هستند، اما برای دستورات کوتاه متداول مانند diff که نیازمند نامفایلها برای منابع ورودیاشان میباشند، بدون نقص هستند.