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

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

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

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

Bad Questions


پرسش‌های نامناسب

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

تقریباً در تمام موارد، علت این موضوع پرسش نامناسب است. پرسش‌های بد برای هیچکس سودی ندارند. وقت شما را هدر می‌دهند، و به معنی آن است که به احتمال بسیار، اشخاص کمک کردن به شما را حتی امتحان نخواهند نمود.

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

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

گم شده در جزئیات

  • من احتیاج دارم، پس از اینکه کلمه‌ای را در یک فایل grep می‌کنم، آن سطر و 4 سطر بعد را حذف کنم. نظری هست؟

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

شخص پرسش کننده سؤال، به هر علت، به اندازه‌ای روی grep متمرکز شده است که این برنامه قسمتی از پرسش گردیده. این مطلب او را نسبت به سایر امکاناتی که grep را فرا نمی‌گیرند، نابینامی‌کند.

برای بدست آوردن پاسخ صحیح، این پرسش را چگونه مجدداً تنظیم نماییم؟

  • می‌خواهم یک کلمه را در فایلی پیدا کنم، وسپس آن سطر و چهار سطر بعدی را از فایل حذف نمایم.

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

کمک کنید راه‌حل خود برای مشکلم را تصحیح کنم

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

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

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

10:24|   Milos | یکی می‌تواند نمونه خوبی به من معرفی کند که برای encode کردن چیزی به کار ببرم و قادر به decode کردن آن هم باشد؟ یعنی ‎رمزنگاری و رمزگشایی دوطرفه‎؟
10:24| lhunath | ‏coding یا crypting؟
10:24| lhunath | شاید openssl‏.
10:25|   Milos | اوه، خوب نه lhunath، فکر می‌کنم اشتباه بیان کردم - من درست چیزی می‌خواهم که بتوانم  ‎"hello this has spaces and *2384"‎ به چیزی مانند ‎0938reksfoiur9owe8gi‎ تبدیل کنم، اما قادر به decode کردن آن به طور برعکس نیز باشم.
10:25| lhunath | مقصود؟
10:25|   Milos | ‏lhunath برای عبور دادن شناسه‌هایی که ممکن است شامل فاصله‌ها یا کاراکترهای خاص باشند.

مشکل اصلی به استفاده از پارامترهای bash برای عبور دادن داده‌ها به سایر برنامه‌ها مربوط می‌گردد. راه حل واقعی، نقل‌قولی کردن پارامترها به طور صحیح، هنگامی که به عنوان شناسه‌ها به کار می‌روند یا روش امن دیگری برای عبور دادن داده‌ها، بود. Encoding شناسه داده‌ای به چیزی دیگر، روش ترسناک اجتناب از تفکیک کلمه bash (به جای خاموش کردن آن با نقل‌قولی کردن) می‌باشد و در این حالت، شخص داده‌ها را به درون یک تفسیر کننده کدِ ‌دیگر تزریق می‌کرد. تزریق داده‌ها در کُد، همواره یک ایده واقعاً نامناسب می‌باشد.

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

پرسش‌های محتوی خطاها

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

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

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

کاربرد مثال ما

  • به طور پیش‌فرض فایل ‎/etc/bashrc‎ وجود ندارد. اگر فروشنده سیستم‌عامل شما آن را فراهم نموده است، این بدان معنی است که آنها نگارش Bash در سیستم خودشان را دستکاری کرده‌اند. برخی فروشندگان چنین می‌کنند، اما شما نباید از گرایش آنها پیروی کنید. اگر اتفاقاً یک فایل /etc/bashrc پیدا کردید، قطعاً به این فایل (یا فایل ‎/etc/bash.bashrc‎ -- که گاهی اوقات استفاده می‌شود)نباید چیزی اضافه کنید. در حقیقت، اگر موردی داخل یک فایل ‎/etc/bashrc‎ هست که باعث رنجش شما می‌گردد، تنها آن را حذف نمایید!

  • مسئله بزرگتر با فایل ‎/etc/bashrc‎ یا فایلهایی مشابه آن این است که بعضی اشخاص معتقدند که می‌دانند برای کاربرانشان چه چیزی بهتر است، و می‌خواهند محیط کاربرانشان را کنترل کنند. از طرف دیگر، Unix اعتقاد دارد که کاربران بهتر می‌دانند چه چیزی را می‌خواهند، و باید کنترل محیط خودشان را داشته باشند. استفاده از فایل متمرکز شده بر ‎/etc/bashrc‎-شکل، مغایر ماهیت Unix است. ‎~/.bashrc‎ شامل مستعارها، توابع و تنظیمات به شدت شخصی می‌باشد. توجیه قابل‌قبولی برای تحمیل یک انتخاب شخصی از مستعارها (مخصوصاً موارد مشمئز کننده ناگواری مانند ‎alias rm='rm -i'‎) برای جملگی کاربران! وجود ندارد.

  • معمولاً شما نیاز ندارید متغیر ‎PROMPT_COMMAND‎ را برای نمایش یک اعلان به کار ببرید. به جای آن لازم است از PS1 استفاده کنید. محتویات PS1 (با رشته‌های backslash معین که در لحظه توسط Bash تفسیر می‌گردند) هر نوبت که لازم باشد Bash اعلان را نشان بدهد، نمایش داده می‌شوند. از طرف دیگر ‎PROMPT_COMMAND‎، مجموعه‌ای از دستورات است( در عوض مواردی برای نمایش) که درست قبل ازآن که PS1 نمایش داده شود، اجرا می‌گردند. PROMPT_COMMAND برای تنظیم متغیرهایی که PS1 استفاده خواهد نمود، یا برای انجام عملیاتی خارج از اعلان، می‌تواند به کار برود.

  • اکنون، با در نظر داشتن این موارد، شاید شخص مهیای رسیدگی به آن گردد که، فروشنده سیستم عامل شما چه بیرحمی مرتکب گردیده و آن را خنثی نماید. یک رسیدگی کننده حداقل نیاز دارد که بداند:

    • چه موردی در فایل ‎/etc/bashrc‎ مشکل ساز است.

    • در متغیر PROMPT_COMMAND چه چیزی آزار دهنده است.

    • چه چیزی در متغیر PS1 می‌باشد.

    و مطابق معمول، شخص باید بداند:
    • شما می‌خواهید اعلان شما چطور به نظر آید.

این فقط یک نمونه است. مشکل پرسش‌های محتوی خطاها کاملاً شایع می‌باشد و به افراط به طور مکرر ظاهر می‌شود.


  • پرسش‌های بد (آخرین ویرایش ‎2011-04-02 13:35:41‎ توسط GreyCat)

  1. مترجم: برای مطالعه بیشتر، سند جامع «چگونه هوشمندانه سؤال کنیم» نوشته اریک ردموند و ترجمه آقایان سعید رسولی و شایان سیف با ویرایش آقای امیر مهری را که قبلاً در ویکی انجمن‌های اوبونتو فارسی (‎http://wiki.ubuntu-ir.org/SmartQuestions‎) منتشر گردیده، ملاحظه نمایید. (بازگشت)


مشکل در قطع ارتباط با ssh


وقتی من می‌خواهم بعد از اجرای یک job پس‌زمینه‌ای راه دور قطع ارتباط کنم، سرویس‌گیرنده ssh من هنگ می‌کند !

کُد زیر آنچه را انتظار دارید، انجام نخواهد داد:

   ssh me@remotehost 'sleep 120 &'
   # Client hangs for 120 seconds

این ویژگی OpenSSH می‌باشد. سرویس‌گیرنده تا وقتی که ترمینال راه دور هنوز در حال استفاده است، ارتباط را قطع نمی‌کند -- و در حالت ‎sleep 120 &‎، بازهم stdout و stderr به ترمینال متصل هستند.

پاسخ بی‌درنگ به این پرسش شما -- «چگونه می‌توانم ارتباط سرویس گیرنده را قطع کنم به طوری که اعلان پوسته را پس بگیرم؟» -- kill کردن سرویس گیرنده ssh است. البته می‌توانید این کار را با فرمانهای kill یا pkill، یا با ارسال سیگنال INT (معمولاً‎ Ctrl-C ‎) برای یک نشست ssh غیرمحاوره‌ای(مانند بالا)، یا برای پوسته محاوره‌ای راه دور با فشردن کلیدهای ‎ <Enter><~><.>‎ (اینتر، مد، نقطه) در پنجره ترمینال سرویس گیرنده، انجام بدهید.

چاره‌جویی طولانی‌تر این مورد، تأمین نمودن آنست که در طرف راه دور تمام توصیف‌گرهای فایل به فایل ثبت وقایع (یا به ‎/dev/null‎) تغییر مسیر داده شوند:

   ssh me@remotehost 'sleep 120 >/dev/null 2>&1 &'
   # فوراً باز می‌گردد

همچنین این مورد در برخی سیستم‌های یونیکسی قدیمی سرویسهای کمکی (daemon) را دوباره راه‌اندازی می‌کند.

   ssh root@hp-ux-box             # پوسته محاوره‌ای‎
   ...                            # روشن می‌کند که مشکل در سیستم‌فایل شبکه است‎
   /sbin/init.d/nfs.client stop   # با این اسکریپت مدیریت می‌شود و autofs 
   /sbin/init.d/nfs.client start  # قبول است (برخلاف لینوکس )‏ HP-UX کشتن آن در
   exit
   # آنرا بکُشید Enter ~ . سرویس گیرنده هنگ می‌کند با استفاده از 

لطفاً توجه نمایید که تحت SSH اجازه دادن به root برای ایجاد فایل ثبت رخداد، از نظر امنیتی، عادت بسیار بدی است. اگر شما باید این کار را انجام بدهید، پس یک اسکریپت منفرد ایجاد کنید که تمام دستورهای مورد نظر شما را بدون هیچ گزینه خط فرمان اجرا کند، و سپس فایل sudoers را طوری پیکربندی کنید که به یک کاربر مناسب بدون نیاز به کلمه عبور اجازه اجرای اسکریپت اشاره شده را بدهد. این کار متضمن آن خواهد بود که شما آگاه باشید چه فرمانهایی لازم است به طور مرتب اجرا بشوند و در صورتی که حساب کاربری مقرر در خطر فاش شدن قرار گیرد، خسارتی که می‌تواند وارد شود، محدود می‌گردد.

اسکریپت ‎/sbin/init.d/nfs.client‎ میراث یونیکس، سرویس‌های کمکی را در پس‌زمینه اجرا می‌کند اما اجازه می‌دهد stdout و stderr آنها به ترمینال متصل شوند(و آنها به طور کامل self-daemonize نیستند). راه حل آن یا تعمیر اسکریپت ناقص init فروشنده یونیکس، یاکُشتن پردازش سرویس گیرنده ssh پس از وقوع این مورد است. مؤلف این گفتار از رویکرد اخیر استفاده می‌کند.


پرسش و پاسخ 63 (آخرین ویرایش ‎2011-08-05 18:02:00‎ توسط GreyCat)


ایجاد فایل موقتی به طور بی‌خطر


چطور می‌توانم در یک حالت ایمِن، یک فایل موقتی ایجاد کنم؟

به نظر نمی‌رسد هیچ فرمان منفردی وجود داشته باشد که واقعاً در همه جا کار بکند. tempfile قابل حمل نیست. mktemp به طور وسیع‌تری موجود است( اما باز هم به طور در همه جا حاضر نیست)، فقط ممکن است برای ایجاد فایل از قبل، مستلزم گزینه ‎ -c‎ باشد، یا ممکن است به طور پیش‌فرض فایل را ایجاد کند و اگر ‎ -c‎ فراهم شده باشد، ناموفق گردد. برخی سیستم‌ها هیچ یک از دو فرمان را ندارند(سولاریس و POSIX).

پاسخ سنتی به طور معمول چیزی مانند این بوده:

  #   استفاده نکنید! وضعیت مسابقه!
   tempfile=/tmp/myname.$$
   trap 'rm -f "$tempfile"; exit 1' 1 2 3 15
   rm -f "$tempfile"
   touch "$tempfile"

مشکل با این مورد عبارت است از: اگر فایل از قبل موجود باشد(برای مثال، به عنوان یک لینک به ‎ /etc/passwd‎)، آنوقت ممکن است اسکریپت مواردی را در محل‌هایی بنویسد که نباید نوشته شوند. حتی اگر شما فایل را فوراً قبل از استفاده از آن حذف کنید،، بازهم یکوضعیت مسابقه دارید: شخصی می‌تواند در فاصله مابین دستورات پوسته شما یک لینک بداندیشانه بازتولید نماید.

بهترین پاسخ قابل حمل قرار دادن فایلهای موقتی در دایرکتوری خانگی خودتان (یا بعضی دایرکتوری‌های شخصی دیگر) است، جایی که هیچ فرد دیگری مجوز نوشتن ندارد. آنوقت لااقل نگرانی در مورد کاربران بداندیش را ندارید. طرح‌های ساده مبتنی بر PID (یا نام میزبان + ‎PID‎ برای سیستم فایل‌های به اشتراک گذاشته شده) جهت پیش‌گیری از تداخل با اسکریپت‌های خودتان، کفایت خواهد نمود.

متأسفانه، به نظر نمی‌رسد افراد این پاسخ را دوست داشته باشند. آنها خواستار آن هستند که فایلهای موقتی‌شان در ‎/tmp‎ یا ‎/var/tmp‎ باشند. برای آن افراد، روش پاکیزه‌ای وجود ندارد، بنابراین آنها باید روش هوشمندانه(hack)ای که می‌توانند با آن ادامه بدهند را انتخاب کنند.

ساختن یک دایرکتوری موقتی

در برخی سیستم‌ها(مانند لینوکس):

  • شما دارای فرمان معتبر mktemp می‌باشید و می‌توانید از گزینه ‎-d‎ آن استفاده نمایید، برای اینکه دایرکتوری‌های موقتی ایجاد می‌کند که تنها برای شما قابل دستیابی است، همراه با کاراکترهای تصادفی در نام آنها جهت تقریباً غیر ممکن نمودن حدس زدن پیشاپیشن نام دایرکتوری برای یک مهاجم.

  • می‌توانید فایلهایی با نام طولانی‌تر از ۱۴ کاراکتر در ‎/tmp‎ ایجاد کنید. ‎

  • شما Bash را در دسترس دارید بنابراین از ویژگی‌های مخصوص آن برای این کار استفاده کنید.

   # POSIX در‎

   # تنظیم می‌کند ‎"/tmp"‎  از قبل دارای مقدار نباشد آن را به ‎$TMPDIR‎ فقط در صورتیکه‎
   : ${TMPDIR:=/tmp}

   # ببینیم ‎http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html‎ این صفحه را ‎$TMPDIR‎ می‌توانیم در باره‎

   # ایجاد کنید ‎$TMPDIR‎ یک دایرکتوری موقتی خصوصی در‎
   # وقتی اسکریپت خاتمه می‌یابد دایرکتوری موقتی را حذف کنید‎
   unset temporary_dir
   trap '[ "$temporary_dir" ] && rm -rf "$temporary_dir"' EXIT

   save_mask=$(umask)
   umask 077
   temporary_dir=$(mktemp -d "$TMPDIR/XXXXXXXXXXXXXXXXXXXXXXXXXXXXX") || { echo "ERROR creating a temporary file" >&2; exit 1; }
   umask "$save_mask"

و آنوقت می‌توانید فایلهای ویژه خود را در دایرکتوری موقتی ایجاد کنید.


یک پیشنهاد متفاوت که به فرمان mktemp نیاز ندارد: با استفاده از متغیر RANDOM به صورت زیر، یک دایرکتوری موقتی که بعید است با نام یک دایرکتوری موجود مطابقت بنماید، می‌تواند ایجاد گردد:

   temp_dir=/tmp/$RANDOM
   mkdir "$temp_dir"

این کد یک دایرکتوری به شکل ‎/tmp/20445/‎ ایجاد خواهد نمود‎. برای کاهش احتمال برخورد با نام یک دایرکتوری موجود، متغیر RANDOM می‌تواند چندبار به کار برود، یا با ID پردازش ترکیب بشود:

   temp_dir=/tmp/$RANDOM-$$
   mkdir -m 700 "$temp_dir" || { echo "failed to create temp_dir" >&2; exit 1; }

این کد یک دایرکتوری به صورت ‎/tmp/24953-2875/‎ ایجاد خواهد نمود. این مورد از یک موقعیت مسابقه اجتناب می‌کند، به علت اینکه mkdir همانطور که در پرسش و پاسخ ۴۵ می‌بینیم، تجزیه ناپذیر(اتمی) است. لازم‌الاجراست که شما نتیجهmkdir را کنترل نمایید، در صورتی که در ایجاد دایرکتوری ناموفق باشد ، واضح است که نمی‌توانید پیش بروید.

(برخی سیستم‌ها دارای محدودیت ۱۴ کاراکتر در نام فایل هستند، بنابراین از آزمایش ترکیب بیش از دوبارِ رشته ‎$RANDOM‎ همراه یکدیگر اجتناب کنید. شما برای امنیت خود به تجزیه ‌ناپذیری mkdir استناد می‌کنید، نه برای گمنامی نام تصادفی انتخابی. اگر شخصی دایرکتوری ‎/tmp‎ را با صدهاهزار فایلهای دارای نام عدد تصادفی به منظور انسداد راه شما، پُر کند، با مسایل بزرگتری مواجه هستید.)


به جای RANDOM، می‌توان از awk برای تولید عدد تصادفی به یک روش سازگار با POSIX استفاده نمود:

   temp_dir=/tmp/$(awk 'BEGIN { srand (); print rand() }')
   mkdir -m 700 "$temp_dir"

توجه کنید، به هر حال، آن srand()‎ سرچشمهِ تولید عدد تصادفی، از ثانیه‌ها نسبت به epoch زیرنویس 1 استفاده می‌کند که پیش بینی کردن آن برای یک متخاصم و انجام حمله پرده‌پوشی سرویس(DoS)، به طور مساعدی آسان است.

با ترکیب فوق می‌توانیم به کار ببریم:

   temp_dir=/tmp/"$(awk -v p=$$ 'BEGIN { srand(); s = rand(); sub(/^0./, "", s); printf("%X_%X", p, s) }')"
   mkdir -m 700 "$temp_dir" || { echo '!! unable to create a tempdir' >&2; exit 1; }

چون در awk قالب عددی پیش‌فرض ‎%g‎ می‌باشد که معادل شش رقم بعد از نقطه اعشار است، ما یک دنباله شش رقمی داریم. 999,999 به صورت هگز می‌شود F423F که یک کاراکتر به ما پس می‌دهد، یکی دیگر برای _ و 8 کاراکتر برای پیشوند نمودن pid در سیستم فایل ۱۴ کاراکتری در دسترس است. یک شماره شناسایی پردازش(pid) سی و دو بیتی بدون علامت، حداکثر ۸ رقم هگز خواهد شد، بنابراین مورد فوق در اکثر مکان‌هایی که ممکن است شخصی با چنین سیستم فایلی روبرو گردد، کار می‌کند. و البته چنانکه greycat اشاره نمود، موقع وجود کمبودها، از تنگنا رها می‌شویم.

  • آیا این یک مقداری غیر منطقی نمی‌باشد؟ -- GreyCat

  • نه چندان بیش از رویکرد غیرقابل حمل ارائه شده فوق. نقطه نظر مکرر شما در باره محدودیت ۱۴ کاراکتری در سیستم‌فایلها را جواب می‌دهد، و استفاده از ‎ /tmp‎ که برخی مدیران سیستم ترجیح می‌دهند را میسر می‌سازد، و در صورتی که اسکریپت یک برنامه تعریف شده با یک نام خاص نباشد، می‌تواند سودمند واقع گردد، در آن حالت من موافق هستم که داشتن یک دایرکتوری معین تحت ‎$HOME‎ یا جای دیگر، رویکرد بهتری می‌باشد. به عنوان یک موضوع فرعی، پیشوند pid درجه‌ای از کنترل یا آگاهی بر هر دایرکتوری موقتی ایجاد شده را فعال می‌کند. شخصاً ترجیح می‌دهم این مورد را در ترکیب با فراخوان‌های trap و استفاده از ‎$TMPDIR‎ ، که برای ‎POSIX sh‎ قابل حمل است را داشته باشم تا فراخوانی mktemp که من نمی‌توانم به آن تکیه کنم. -- igli

سایر راهکارها

من تصریح می‌کنم که بهترین راه‌حل برای نگهداری فایلهای اختصاصی شما استفاده از دایرکتوری ‎$HOME‎ شما می‌باشد. اگر شما در حال پیاده‌سازی یک سرویس کمکی یا موردی هستید که تحت یک حساب کاربری اجرا می‌شود، چرا به سادگی یک دایرکتوری اختصاصی برای آن سرویس در همان زمانی که آن کد را نصب می‌کنید، نسازید؟


یک پیشنهاد نه کاملاً جدی دیگر پیوست کردن کُد C در اسکریپتی است که فرمان ‎mktemp(1)‎ را برمبنای تابع کتابخانه‌ای‎ mktemp(3)‎ پیاده‌سازی میکند. اما این کار دو مشکل دارد:

  • بلااستفاده در سیستم‌های سولاریس، جایی که به این نیاز خواهیم داشت احتمالاً کامپایلر C را نداریم.
  • مسئله مرغ و تخم مرغ: ما برای نگهداری خروجی کامپایلر به نام فایل موقتی نیاز داریم.


پرسش و پاسخ 62 (آخرین ویرایش ‎2013-01-11 04:00:34 توسط 82)


  1. مترجم: عبارتی که در ابتدا درمستندات یونیکس برای ساعت وتاریخ صفر سیستم عامل به کار رفته است، و در اکثر نگارشهای یونیکس برابر نیمه شب اول ژانویه 1970 به وقت ‎UTC (برگرفته از Universal Time Coordinated‎ روش مدرن و دقیقتر از وقت گرینویچ برای محاسبه یکنواخت زمان در تمام نقاط جهان است و ساعت اتمی بین‌المللی نیز گفته می‌شود)‎ می‌باشد. ساعت سیستم که در نشانه‌های زمان فایلها ثبت می‌شود(تاریخ دستیابی، ویرایش یا ایجاد) بر اساس ثانیه‌های سپری شده از epoch است. در لغت، مبداء زمان نیز گفته می‌شود. (بازگشت)


لیست تغییرات Bash در هر نگارش

پرسش و پاسخ شماره ۶۱

آیا لیستی از ویژگی‌های اضافه شده به یک نگارش معین Bash وجود دارد؟

در اینجا پیوندهایی به مستندات رسمی Bash آمده است:

  • NEWS: فایل لیست موجز تغییرات بین نگارش جاری و نگارش قبلی

  • CHANGES: تاریخچه کامل تغییرات bash (فقط از نگارش2.0 به بعد)

  • COMPAT: مسائل سازگاری بین bash3 و نگارش‌های قبلی

لیست خلاصه گسترده‌تر از لیست پایین می‌تواند دراینجا یافت شود تغییرات Bash

این هم لیست جزئی تغییرات، در یک قالب فشرده‌تر:

ویژگی

اضافه شده در نگارش

\uXXXX and \UXXXXXXXX

4.2-alpha

declare -g

4.2-alpha

test -v

4.2-alpha

printf %(fmt)T

4.2-alpha

array[-idx] and ${var:start:-len}

4.2-alpha

lastpipe (shopt)

4.2-alpha

read -N

4.1-alpha

{var}> or {var}< etc. (FD variable assignment)

4.1-alpha

syslog history (compile option)

4.1-alpha

BASH_XTRACEFD

4.1-alpha

;& and ;;& fall-throughs for case

4.0-alpha

associative arrays

4.0-alpha

&>> and |&

4.0-alpha

command_not_found_handle

4.0-alpha

coproc

4.0-alpha

globstar

4.0-alpha

mapfile/readarray

4.0-alpha

${var,[,]} and ${var^[^]}

4.0-alpha

{009..012} (leading zeros in brace expansions)

4.0-alpha

{x..y..incr}

4.0-alpha

read -t 0

4.0-alpha

read -i

4.0-alpha

x+=string array+=(string)

3.1-alpha1

printf -v var

3.1-alpha1

{x..y}

3.0-alpha

${!array[@]}

3.0-alpha

[[ =~

3.0-alpha

<<<

2.05b-alpha1

i++

2.04-devel

for ((;;))

2.04-devel

/dev/fd/N, /dev/tcp/host/port, etc.

2.04-devel

a=(*.txt) file expansion

2.03-alpha

extglob

2.02-alpha1

[[

2.02-alpha1

builtin printf

2.02-alpha1

$(< filename)

2.02-alpha1

** (exponentiation)

2.02-alpha1

\xNNN

2.02-alpha1

(( ))

2.0-beta2


پرسش و پاسخ شماره 61 (آخرین ویرایش ‎ 2012-05-07 12:12:43 ‎ توسط geirha)


تعویض دایرکتوری با اسکریپت!


من سعی می‌کنم اسکریپتی بنویسم که دایرکتوری جاری را تغییر دهد( یا یک متغیر را تنظیم کند)، اما بعد از به پایان رسیدن اسکریپت، در همان جایی هستم که از آنجا شروع کرده بودم(یا متغیر من نیست)!

این را ملاحظه نمایید:

   #!/bin/sh
   cd /tmp

اگر شخصی این اسکریپت را اجرا نماید، چه اتفاقی روی می‌دهد؟ Bash منشعب می‌شود که به یک والد(پوسته محاوره‌ای که فرمان در آن تایپ شده) و یک فرزند(پوسته جدیدی که اسکریپت را می‌خواند و اجرا می‌کند) منجر می‌گردد. فرزند اجرا می‌شود، در حالیکه پدر برای خاتمه یافتن آن منتظر می‌ماند. فرزند اسکریپت را می‌خواند و اجرا می‌کند، دایرکتوری جاری آن به ‎ /tmp‎ تغییر می‌کند، و سپس خارج می‌شود. والد که در انتظار فرزند است،کد وضعیت فرزند را تحصیل می‌کند(احتمالاً صفر در اثر موفقیت)، و سپس با دستور بعدی ادامه می‌دهد. هیچ جایی در این پردازش دایرکتوری کاری پدر تغییر نکرده است -- فقط دایرکتوری فرزند تغییر کرد.

پردازش فرزند هرگز بر هیج بخشی از محیط والد، که شامل متغیرهایش، دایرکتوری کاری‌اش، فایلهای بازش، محدودیت منابعش، و غیره می‌شود، اثر نمی‌گذارد.

بنابراین، چطور فردی تقلا می‌کند دایرکتوری جاریوالد را تغییر بدهد؟ هنوز می‌توانید فرمان cd را در یک فایل خارجی داشته باشید، اما نمی‌توانید به عنوان اسکریپت آنرا اجراکنید. اجرای آن باعث انشعابی که قبلاً تشریح شد، می‌گردد. به جای آن شما باید با دستور .(یا دستور source مترادف آن، فقط در Bash) آن را منبع کنید. منبع کردن اساساً به معنی آنست که شما فرمانها را در یک فایل با استفاده از پوسته جاری اجرا می‌کنید، نه در یک پوسته منشعب(شل فرزند):

   echo 'cd /tmp' > "$HOME/mycd"      #‎ ایجاد می‌کند‎ 'cd /tmp' فایلی محتوی فرمان 
   . $HOME/mycd          # در شل جاری 'cd /tmp' آن فایل منبع می‌شود، اجرای فرمان
   pwd                   #  هستیم /tmpاکنون ما در شاخه 

همین مورد در تنظیم متغیرها اِعمال می‌گردد. . ("dot in") فایلی که شامل دستورات است، سعی نمی‌کند آن فایل را اجرا کند.

اگر دستوری که اجرا می‌کنید یک تابع است، نه یک اسکریپت، در پوسته جاری اجرا خواهد شد. بنابراین، ممکن است برای انجام آنچه در مثال فوق سعی کردیم با فایل خارجی انجام بدهیم، بدون احتیاج به هر گونه "dot in" یا "source" یک تابع تعریف شود. تعریف تابع زیر و سپس فراخوانی ساده آن با تایپ mycd:

   mycd() { cd /tmp; }

اگر می‌خواهید به طور خودکار در پوسته جدیدی که باز می‌کنید تابع در دسترس باشد، آن را در ‎ ~/.bashrc یا مشابه آن قرار بدهید.

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

   alias mycd='cd /tmp'  # .معادل تابع نشان داده شده در بالا

   alias cdlstmp='cd /tmp && ls tmp*'
   # شروع می‌شوند "tmp" می‌برد و نشان می‌دهد آنجا کدام فایلها با /tmp شما را به  

   cdls() { cd "$1" && ls; }
   # توسط مستعارها نمی‌تواند انجام شود‎
   #  cdls directory نحوه استفاده

پرسش و پاسخ 60 (آخرین ویرایش ‎ 2012-01-27 22:50:33 ‎ توسط 125)