آموزش‌های خط فرمانی

این وبلاگ تلاش می‌کند گامی در حد بضاعت در جهت آموزش خط فرمان و اسکریپت‌نویسی پوسته گنو-لینوکس بردارد.

آموزش‌های خط فرمانی

این وبلاگ تلاش می‌کند گامی در حد بضاعت در جهت آموزش خط فرمان و اسکریپت‌نویسی پوسته گنو-لینوکس بردارد.

لوله ها(pipes)

ادامه یادداشت قبل


5. لوله‌ها(Pipes)

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

می‌توانید از تغییرمسیرفایل برای نوشتن خروجی در فایلها یا خواندن ورودی از فایلها، استفاده کنید. اما اگر بخواهید خروجی یک برنامه را به طور مستقیم به ورودی برنامه دیگر مربوط کنید چطور؟ از آن طریق می‌توانید زنجیر پیوسته‌ای از پردازش خروجی ایجاد کنید. اگر از قبل درباره FIFOها، آگاه بودید، می‌توانستید با استفاده از چیزی مانند این مثال آن را کامل کنید:

    $ ls
    $ mkfifo myfifo; ls
    myfifo
    $ grep bea myfifo &
    [1] 32635
    $ echo "rat
    > cow
    > deer
    > bear
    > snake" > myfifo
    bear

از دستور mkfifo برای ایجاد یک فایل جدید به نام 'myfifo' در دایرکتوری جاری استفاده کردیم. این یک فایل معمولی نیست، بلکه یک FIFO است(که از عبارت First In, First Out اخذ گردیده). فایلهای FIFO فایلهای ویژه‌ای هستند که جهت داده‌های مبتنی بر First In, First Out به کار می‌روند. وقتی از یک FIFO می‌خوانید، فقط داده‌ها را به محض اینکه پردازش دیگری در آن فایل می‌نویسد، دریافت می‌کنید. همینطور یک FIFO هرگز به طورواقعی محتوی هیچ داده‌ای نیست. تا وقتی که پردازشی در آن نمی‌نویسد، هر گونه عملیات خواندن از FIFO در انتظار رسیدن داده‌های معتبر متوقف می‌گردد. همین کار برای نوشتن در FIFO انجام می‌شود -- نوشتن نیز تا وقتی پردازش دیگری در حال خواندن از FIFO است، متوقف می‌شود.

در مثال ما، FIFO با نام myfifo توسط grep خوانده می‌شود. پردازش grep منتظر می‌ماند تا اطلاعات در FIFO قابل دسترس بشوند . اینکه چرا ما عملگر & را به دستور grep پیوست می‌کنیم، برای آنست که آن را در پس‌زمینه قرار دهیم. به این ترتیب، ما می‌توانیم در حالیکه grep در انتظار داده می‌ماند، به تایپ و اجرای دستورات ادامه بدهیم. دستور echo اطلاعات را به FIFO تغذیه می‌کند. به مجرد اینکه این داده قابل دسترس می‌شود، دستور در حال اجرای grep آن را می‌خواند و پردازش می‌کند. نتیجه نمایش داده می‌شود. ما به طور موفقیت‌آمیزی داده را از دستور echo به فرمان grep فرستاده‌ایم.

اما این فایلهای موقتی یک اذیت واقعی هستند. شاید شما مجوز نوشتن نداشته‌باشید. لازم است به خاطر داشته باشید که فایلهای موقتی که ایجاد نموده‌اید را پاک کنید. لازم است مطمئن شوید که داده‌ها وارد و خارج می‌شوند، یا شاید FIFO به دلیل نامعلومی مسدودسازی را خاتمه دهد.

به خاطر این مسائل، ویژگی ‌دیگری در دسترس قرارگرفته است: لوله‌ها. در اصل، لوله فقط stdout یک فرایند را به stdin فرایند دیگر ارتباط می‌دهد، یعنی لوله‌کشی مؤثر داده‌ها از یک پردازش به دیگری. مجموعه کامل دستوراتی را که به این صورت با هم متصل شده‌اند، خط لوله می‌نامند. بیایید مثال فوق را دوباره امتحان کنیم، اما با استفاده از لوله‌ها:

    $ echo "rat
    > cow
    > deer
    > bear
    > snake" | grep bea
    bear

لوله با استفاده از عملگر | بین دو دستور که با هم متصل می‌گردند، ایجاد می‌شود. stdout دستور قبلی به stdin دستور بعدی متصل می‌گردد. در نتیجه، grep می‌تواند خروجی echo را بخواند و نتیجه عملیات خود را که bear است نمایش بدهد.

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

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

    $ message=Test
    $ echo 'Salut, le monde!' | read message
    $ echo "The message is: $message"
    The message is: Test
    $ echo 'Salut, le monde!' | { read message; echo "The message is: $message"; }
    The message is: Salut, le monde!
    $ echo "The message is: $message"
    The message is: Test

وقتی خط لوله به پایان می‌رسد، پوسته‌های فرعی که برای آن ایجاد شده‌اند نیز خاتمه می‌یابند. همراه با پوسته‌های فرعی، هر تغییر و تبدیل انجام شده در آنها نیز از بین می‌رود. بنابراین مراقب باشید!


  • تکرار مفید:
    لوله‌ها به عنوان پس‌پردازشگر خروجی برنامه‌ها، خیلی جالب هستند. به هرحال، شما بایدمراقب باشید در کاربرد آنها زیاده‌روی نکنید. اگر شما خط‌لوله‌ای که شامل سه برنامه یا بیشتر باشد را به انتها برسانید، وقت آنست که از خود بپرسید آیا در حال انجام امور به روش هوشمندانه‌ای هستید؟ امکان دارد قادر باشید ویژگی‌های بیشتری از برنامه را نسبت به آنچه در یک پس‌پردازش در لوله به کار گرفته‌اید، استفاده کنید. هر دستور جدید در یک خط‌لوله موجب یک پوسته فرعی جدید می‌گردد و یک برنامه جدید باید بارگزاری شود. همچنین این مطلب دنبال کردن منطق اسکریپت شما را دشوار می‌سازد!




ادامه دارد...

Heredocs و Herestrings

ادامه یادداشت قبل


4.3. Heredocها و Herestringها

گاهی نگهداری داده‌ها در یک فایل زائد است. ممکن است فقط مقدار بسیارکمی داشته باشیم -- مناسب برای به راحتی گنجاندن آن در خود اسکریپت .یا ممکن است خواسته باشیم محتوای متغیری را ، بدون آنکه اول آن را در یک فایل بنویسیم، به یک دستور تغییر مسیر بدهیم.

    $ grep proud <<END
    > I am a proud sentence.
    > END
    I am a proud sentence.

این یک Heredoc (یا سند اینجا) می‌باشد. وقتی می‌خواهید یک قطعه کوچک چند سطری داده‌ها را در اسکریپت خود تعبیه کنید Heredocها سودمند هستند. (تعبیه قطعات بزرگ تکنیک نامناسبی است. شما باید منطق خود(کد خودتان) و ورودی خود(داده‌هایتان) را جداگانه و ترجیحاً در فایلهای مختلف نگاه دارید، مگر اینکه داده‌ها جزئی باشند.)

در یک Heredoc، کلمه‌ای برای ایفای نقش نگهبان انتخاب می‌کنیم. هر کلمه‌ای می‌تواند باشد، ما از END در این مثال استفاده کرده‌ایم. کلمه‌ای انتخاب کنید، که درمجموعه داده‌ای شما ظاهر نمی‌شود. تمام سطرهایی که پس از اولین نمونه نگهبان تا رسیدن به دومین نمونه آمده‌اند، برای دستور stdin می‌شوند. دومین نمونه نگهبان، باید خودش یک سطر کامل باشد.

چند مورد متمایز برای Heredocها وجود دارد. به طور معمول، نمی‌توانید آنها را دندانه‌دار کنید، همه فاصله‌هایی که در اینجا برای دندانه‌دار کردن اسکریپت به کار ببرید در stdin ظاهر خواهند شد. رشته پایان دهنده(در مثال ما END) باید در ابتدای سطر باشد.

    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های خود، از این مطلب اجتناب کنید. به هر حال، موجب بدشکل شدن تورفتگی شکیل و زیبای شما می‌گردد. یک جایگزین وجود دارد. اگر از ‎<<-END‎ به جای ‎<<END به عنوان عملگر Heredoc خود استفاده کنید، BASH همه کاراکترهای tab در ابتدای هر سطر از محتوای Heredoc شما را قبل از ارسال به دستور حذف می‌کند. به این ترتیب بازهم می‌توانید از tabها (اما از فاصله خیر) برای توگذاری محتوای Heredoc خود با بقیه کد استفاده کنید. آن tabها برای فرمانی که Heredoc شما را دریافت می‌کند، ارسال نخواهند شد. همچنین می‌توانید tabها را برای توگذاری رشته نگهبان هم به کار ببرید.

به طور پیش‌فرض، جایگزینی‌های 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 خیلی مشابه اما فشرده‌تر را آزمایش کنیم:

    $ grep proud <<<"I am a proud sentence"
    I am a proud sentence.

این‌دفعه، stdin مستقیماً اطلاعاتش را از رشته‌ای که پس از عملگر ‎ <<<‎ قرار داده‌اید، می‌خواند. این برای ارسال اطلاعات داخل متغیرها، به پردازش‌ها خیلی مناسب است:

    $ grep proud <<<"$USER sits proudly on his throne in $HOSTNAME."
    lhunath sits proudly on his throne in Lyndir.

Herestringها کوتاه‌تر، کمتر مزاحم، و به طور کلی مناسب‌تر از Heredocهای حجیم همتای خود می‌باشند. گرچه آنها قابل حمل به پوسته Bourne نیستند.

بعداً، شما در باره لوله‌ها و اینکه چطور می‌توانند برای ارسال خروجی یک دستور به stdin دستور دیگر به کار بروند، خواهید آموخت. افراد بسیاری برای ارسال خروجی یک متغیر به عنوان stdin برای یک فرمان، از لوله‌ها استفاده می‌کنند. گرچه، برای این مقصود Herestringها باید ترجیح داده شوند. آنها پوسته فرعی ایجاد نمی‌کنند و برای پوسته و هم برای سبک نگارش اسکریپت پوسته شما روشن‌تر هستند:

    $ echo 'Wrap this silly sentence.' | fmt -t -w 20
    Wrap this silly
       sentence.
    $ fmt -t -w 20 <<< 'Wrap this silly sentence.'
    Wrap this silly
       sentence.


  • تکرار مفید:
    heredocهای بلند به طور معمول ایده نامناسبی هستند، زیرا اسکریپت‌ها باید محتوی منطق باشند، نه داده‌ها. اگر اسکریپت به سند حجیمی نیاز دارد، باید آن را در یک فایل جداگانه با اسکریپت همراه کنید. با این وجود Herestringها، اغلب کاملاً سودمند هستند بویژه برای ارسال محتوای یک متغیر(به جای فایلها) به فیلترهایی مانند grep یا sed.



ادامه دارد...