فصل ۶ – تغییر مسیر ورودی و خروجی (Redirection)
مقدمه
تقریباً تمام دستورات خط فرمان دادههایی تولید میکنند یا دادههایی مصرف میکنند.
به طور پیشفرض خروجی آنها روی صفحه ظاهر میشود و هر ورودی مورد نیاز از صفحهکلید خوانده میشود.
اما شل این امکان را فراهم میکند که جریان ورود و خروج دادهها را دقیقاً همانطور که میخواهیم هدایت کنیم؛
میتوانیم نتیجهی دستورات را در فایلها ذخیره کنیم، خروجی چند دستور را به هم متصل کنیم، یا حتی
یک فرمان را به عنوان منبع دادهی فرمان دیگر قرار دهیم.
در این فصل به مباحث زیر میپردازیم:
- جریانهای استاندارد داده در یونیکس/لینوکس
- تغییر مسیر خروجی استاندارد با
>و>> - مدیریت خطاها با
2>و ترکیب جریانها - جلوگیری از رونویسی ناخواسته با
noclobber - خواندن ورودی از فایلها با
< - استفاده از
catبرای ترکیب و ایجاد فایلها - ساخت لولههای پردازش (
pipeline) با| - آشنایی با فیلترهای متداول مانند
sort،uniq،wc،grep،fmt،pr،headوtail - ذخیره و مشاهدهی همزمان خروجی با
tee
ورودی و خروجی استاندارد
هر دستور حداقل با سه «جریان» (stream) سروکار دارد:
- ورودی استاندارد (Standard Input یا
stdin): جریان دادهای که دستور از آن میخواند. به طور پیشفرض صفحهکلید است. - خروجی استاندارد (Standard Output یا
stdout): جریان دادهای که دستور نتایج معمول خود را در آن مینویسد. پیشفرض نمایشگر (ترمینال) است. - خروجی خطای استاندارد (Standard Error یا
stderr): جریان جداگانهای برای پیامهای خطا و هشدارها. آن هم پیشفرض روی نمایشگر است.
در پشت صحنه، سیستمعامل برای این جریانها شمارههایی در نظر میگیرد که «توصیفگر فایل» (file descriptor) نام دارند:
0برایstdin1برایstdout2برایstderr
شناخت این مفاهیم ضروری است، زیرا هنگام تغییر مسیر مشخص میکنیم کدام یک از این جریانها باید به مقصد دیگری هدایت شود.
تغییر مسیر خروجی استاندارد
برای هدایت خروجی معمول یک دستور به داخل فایل از عملگر > استفاده میکنیم:
ls > ls-output.txt
این دستور خروجی ls را در فایل ls-output.txt ذخیره میکند. اگر فایل از قبل وجود داشته باشد جایگزین میشود.
در صورت نیاز به افزودن خروجی جدید به انتهای فایل بدون حذف محتوا از >> کمک میگیریم:
ls >> ls-output.txt
گاهی میخواهیم خروجی را دور بریزیم. دستگاه ویژهای به نام /dev/null وجود دارد که هر دادهای به آن ارسال شود ناپدید میگردد:
ls -l /usr/bin > /dev/null
این روش برای ساکتکردن برنامهها هنگام اجرای اسکریپتها مفید است.
تغییر مسیر پیامهای خطا
اگر دستوری هم خروجی معمول و هم پیام خطا تولید کند، میتوانیم آنها را جداگانه مدیریت کنیم. برای ارسال stderr به فایل از 2> استفاده میکنیم:
ls -l /not-here 2> ls-errors.txt
برای افزودن پیامهای خطا به انتهای فایل موجود:
ls -l /not-here 2>> ls-errors.txt
ارسال همزمان stdout و stderr به یک فایل نیز ممکن است. یکی از روشهای رایج استفاده از &> است:
ls -l /usr/bin &> ls-full.log
یا میتوانیم stderr را به stdout هدایت کنیم و سپس آنها را با هم تغییر مسیر دهیم:
ls -l /usr/bin > ls-full.log 2>&1
در این مثال ابتدا stdout به فایل میرود و سپس stderr به همان مقصد هدایت میشود.
محافظت در برابر رونویسی ناخواسته
گاهی فراموش میکنیم فایلی وجود دارد و با > آن را از بین میبریم. برای جلوگیری از این اتفاق، شل bash گزینهای به نام noclobber دارد:
set -o noclobber
ls > ls-output.txt # اگر فایل وجود داشته باشد خطا میدهد.
برای اجازهی رونویسی موقتی بدون غیرفعال کردن noclobber میتوان از >| استفاده کرد:
ls >| ls-output.txt
برای بازگشت به رفتار پیشفرض و اجازهی رونویسی کافی است noclobber را خاموش کنیم:
set +o noclobber
تغییر مسیر ورودی استاندارد
همانطور که خروجی را هدایت میکنیم، میتوانیم ورودی یک دستور را هم از فایل بگیریم. عملگر < این کار را انجام میدهد:
sort < unsorted-list.txt
در این مثال، sort دادهها را به جای صفحهکلید از فایل میخواند و نتیجه را روی نمایشگر مینویسد.
استفادههای کاربردی از cat
دستور cat (مخفف concatenate) برای نمایش محتویات فایلها و اتصال آنها استفاده میشود:
cat ls-output.txt
با ترکیب cat و تغییر مسیر خروجی میتوانیم چند فایل را در یکی ادغام کنیم:
cat part1.txt part2.txt > whole.txt
علاوه بر این میتوانیم با اجرای cat > note.txt فایلی تازه بسازیم و متن دلخواه را تایپ کنیم؛ فشردن کلیدهای Ctrl+D (در لینوکس) پایان ورودی را اعلام میکند. برای افزودن متن جدید به همان فایل نیز میتوانیم از cat >> note.txt استفاده کنیم.
یا خروجی یک دستور را به عنوان ورودی cat بدهیم و نتیجه را ثبت کنیم:
cat <<MARKER > memo.txt
لطفاً گزارش را تا سهشنبه ارسال کنید.
با تشکر
MARKER
در مثال بالا، از «تغییر مسیر درونخطی» (here document) استفاده کردیم؛ هر چیزی بین MARKER اول و دوم نوشته شود، به عنوان ورودی cat در نظر گرفته میشود.
لولهکشی دادهها با |
علاوه بر فایلها، میتوان خروجی یک دستور را مستقیماً به ورودی دستور بعدی وصل کرد. عملگر | یا «pipe» این کار را انجام میدهد:
ls -l /usr/bin | less
در اینجا، ls خروجی مفصل خود را تولید میکند و less همان خروجی را صفحهبهصفحه نمایش میدهد. زنجیرههای طولانیتری هم میتوانیم بسازیم:
cat /etc/passwd | sort | less
هر فرمانی که داده را از ورودی استاندارد میخواند و روی خروجی استاندارد مینویسد، در لولهها قابل استفاده است.
فیلترهای پرکاربرد
فیلتر به دستوری گفته میشود که داده را از ورودی استاندارد میگیرد، پردازش میکند و نتیجه را روی خروجی استاندارد میگذارد. چند نمونهی مهم عبارتند از:
sort– دادهها را بر اساس ترتیب الفبایی یا با گزینههای دیگر مرتب میکند.uniq– خطوط تکراری را حذف یا تعداد تکرارها را گزارش میدهد (معمولاً بعد ازsortاستفاده میشود).wc– تعداد خطوط، کلمات و بایتهای ورودی را میشمارد. گزینهی-lفقط خطوط را گزارش میدهد.grep– خطوطی را که با الگوی دادهشده (عبارت منظم) مطابقت دارند انتخاب میکند.fmt– متن را با عرض ثابت مرتب میکند؛ برای بازآرایی پاراگرافها مفید است.pr– متن را برای چاپ روی صفحه آماده میکند و سرفصلها و شمارهی صفحه اضافه میکند.head– نخستین خطوط ورودی را نشان میدهد (پیشفرض ۱۰ خط).tail– آخرین خطوط ورودی را نمایش میدهد؛ گزینهی-fتغییرات زندهی فایل را دنبال میکند.
با ترکیب این فیلترها میتوانیم فرآیندهای پردازشی پیچیدهای بسازیم بدون آنکه لازم باشد اسکریپتهای طولانی بنویسیم.
مثال:
ls /usr/bin | sort | uniq | head
نگه داشتن و مشاهدهی همزمان خروجی با tee
گاهی لازم است خروجی یک لوله، هم برای ادامهی پردازش استفاده شود و هم در فایل ذخیره گردد.
دستور tee درست مثل اتصال سهراهی عمل میکند: دادهی ورودی را روی خروجی استاندارد میریزد و همزمان نسخهای از آن را در فایل مورد نظر ذخیره میکند.
ls -l /usr/bin | tee ls.log | less
در این مثال، خروجی مفصل ls برای مشاهده به less میرود و tee همان خروجی را در ls.log ذخیره میکند. با گزینهی -a میتوانیم دادهها را به انتهای فایل بیفزاییم:
command | tee -a combined.log
جمعبندی
تغییر مسیر ورودی و خروجی یکی از مهمترین مهارتهای کار با خط فرمان است. با دانستن نحوهی هدایت جریانهای استاندارد میتوانیم دستورات ساده را به زنجیرههای قدرتمند تبدیل کنیم، خروجیها را ذخیره یا پالایش کنیم، و فرآیندهای خودکار بسازیم. ترکیب >، >>، <، |، فیلترها و tee آزادی عمل چشمگیری به ما میدهد تا هر نوع پردازش متنی را انجام دهیم.