منبع اصلی نوشتار زیر در این لینک قرار دارد

انواع redirection و تفاوت آنها


به طور کلی در باره ‎2>&1‎ بگویید -- تفاوت بین ‎2>&1 >foo‎ و ‎>foo 2>&1‎ چیست، و چه‌وقت می‌توانم از هرکدام استفاده کنم؟

تمام پردازشهای Bash به ترتیب از چپ به راست تغییر مسیر داده می‌شوند. و ترتیب معنا دار است. انحراف از آن در یک فرمان ممکن است نتایج آن فرمان را تغییر بدهد.

اگر تمام آنچه می‌خواهید ارسال هر دو خروجی استاندارد و خطای استاندارد به یک فایل است، این مورد را به کار ببرید:

# Bourne
foo >file 2>&1          # هر دو را به فایل ارسال می‌کند stdout و stderr 

این هم یک نمایش ساده از آنچه اتفاق می‌افتد:

# POSIX
foo() {
  echo "This is stdout"
  echo "This is stderr" 1>&2
}
foo >/dev/null 2>&1             # هیج خروجی ارائه نمی‌کند 
foo 2>&1 >/dev/null             # "This is stderr" در نمایشگر می‌نویسد

چرا نتایج اختلاف دارند؟ در حالت اول،‎>/dev/null‎ ابتدا انجام می‌شود، و بنابراین، خروجی استاندارد فرمان به ‎ /dev/null‎ فرستاده می‌شود. سپس، ‎ 2>&1‎ انجام می‌شود، که باعث می‌شود استاندارد خطا به همان جایی ارسال شود که خروجی استاندارد از قبل می‌رفت. بنابراین هر دو خروجی، دور انداخته می‌شوند.

در مثال دوم،‎ 2>&1‎ اول انجام می‌شود. این به معنای آن است که ابتدا خطای استاندارد به جایی ارسال می‌شود که خروجی استاندارد به آنجا می‌رود --در این حالت، به ترمینال کاربر. پس از آن، خروجی استاندارد به ‎ /dev/null‎ فرستاده می‌شود و بنابراین دور انداخته می‌شود. از آن جهت موقعی که ما foo را دفعه دوم اجرا می‌کنیم، فقط خطای استانداردش را می‌بینیم، نه خروجی استاندارد آن را.

فصل تغییر مسیر در راهنما شرح می‌دهد که چرا ما دونسخه‌ای نمودن توصیف‌گر فایل را به جای دوبار باز کردن ‎ /dev/null‎ به کار می‌بریم. در حالت خاصِ ‎ /dev/null ‎  واقعاً مسئله‌ای نیست زیرا تمام نوشته‌ها رها می‌شوند، اما موقعی که ما در فایل ثبت وقایع می‌نویسیم، به راستی خیلی زیاد با اهمیت است.

مواقعی هست که ما به راستی می‌خواهیم ‎ 2>&1‎ اول ظاهر شود -- برای یک مثال از این مورد، پرسش و پاسخ شماره 40 را ببینید.

مواقع دیگری هست که شاید از ‎ 2>&1‎ بدون هر تغییر مسیر دیگری استفاده کنیم. ملاحظه نمایید:

# Bourne
find ... 2>&1 | grep "some error"

در این مثال، می‌خواهیم خطای استاندارد find را (به علاوه خروجی استاندارد آن)برای رشته "some error" جستجو کنیم. ‎2>&1‎ در فرمان لوله‌کشی شده خطای استاندارد را مجبور می‌کند همراه با خروجی استاندارد به داخل لوله برود. (موقعی که لوله‌ها و تغییر مسیرها به این طریق مختلط می‌شوند، به خاطر بیاورید: لوله اول قبل از هر تغییر مسیری انجام می‌شود. بنابراین خروجی استاندارد find قبلاً برای اشاره کردن به لوله تنظیم گردیدهاست، پیش از اینکه ما تغییر مسیر ‎ 2>&1‎ را پردازش کنیم.)

اگر ما می‌خواستیم فقط خطای استاندارد را در لوله بخوانیم، و خروجی استاندارد را رها کنیم، می‌توانستیم چنین کنیم:

# Bourne
find ... 2>&1 >/dev/null | grep "some error"

تغییر مسیرها در این مثال بدین گونه پردازش می‌شوند:

  1. اول، لوله ایجاد می‌شود. خروجی find به آن ارسال می‌شود.

  2. بعد، ‎2>&1‎ باعث می‌شود خطای استاندارد find نیز به لوله برود.

  3. عاقبت، ‎>/dev/null‎ موجب می‌گردد خروجی استاندارد findدور انداخته شود، فقط خطای استاندارد اجازه رفتن به لوله دارد.

یک پرسش مرتبط پرسش و پاسخ شماره 47 است، که چگونگی ارسال stderr به خط لوله را بحث می‌کند.

برای یک توضیح بیشتر گرافیکی قابل درک نمودن عملگر کپی توصیف‌گر فایل را ببینید.

اگر بازهم سر در گم هستید...

اگر هنوز در مورد این نکته سر در گم هستید، احتمال دارد به علت آن باشد که شما با تصور غلطی در مورد چگونگی کار توصیف‌گرهای فایل آغاز نموده‌اید, و هنوز نمی‌توانید آن تصور غلط را رها کنید. نگران نشوید -- این یک موردِ به شدت رایجِ تصور غلط است، و شما تنها نیستید. اجازه بدهید من سعی در تشریح آن بنمایم....

بسیاری اشخاص تصور می‌کنند که ‎ 2>&1‎ یک‌جور «به هم پیوستن» یا «گره زدن با هم» یا « ازدواج کردن» دو توصیف‌گر فایل است، به طوریکه هر تغییر در یکی از آنها تغییری برای دیگری می‌شود. این حالت نیست. و برای بسیاری افراد، این همان جایی است که گیج شدن از آن حاصل می‌شود.

2>&1‎ فقط FD2 را تغییر می‌دهد تا به "آن جایی که FD1 در آن لحظه به آن اشاره می‌کند" اشاره نماید، در واقع باعث نمی‌شود که FD2 به خود FD1 اشاره کند. توجه نمایید که "2" و "1" به سبب روشی که به کار بروند، معانی مختلفی می‌گیرند: "2"، وقتی قبل از ‎ ">&"‎ واقع می‌شود FD2 واقعی معنی می‌دهد، اما "1" که بعد از‎ ">&"‎ واقع می‌شود، به جای خود FD1، به معنی «جایی که FD1 در حال حاضر به آن اشاره می‌کند» است. (اگر برعکس باشد، همچون ‎ "1>&2"‎، آنوقت 1به معنی خود FD1 می‌شود، و 2 به معنی «جایی که FD2 در حال حاضر به آن اشاره می‌کند» خواهد بود.)

شاید قیاس‌ها کمک کنند. یک قیاس در نظر گرفتن FDها به عنوان اشاره‌گرهای C است.

  int some_actual_integer;
  int *fd1, *fd2;

  fd1 = &some_actual_integer;     /* 1>file قابل مقایسه با*/
  fd2 = fd1;                       /*  2>&1 قابل مقایسه با*/
  fd1 = NULL;                      /*  1>&- قابل مقایسه با‎*/

   /* هنوز به مکان واقعی حافظه اشاره می‌کند fd2 در این نقطه‎
      هر دو باید به  یک نقطه اشاره کنند fd2 و fd1 این واقعیت که‎
     مناسب نیست. می‌توانیم یکی از آنها را ببندیم یا دوباره باز کنیم‎
      بدون تأثیر بر دیگری */

یک قیاس دیگر در نظر گرفتن آنها مانند hardlinkها در سیستم فایل است .

   touch some_real_file
   ln some_real_file fd1  # یک لینک به فایل ما ایجاد می‌کند fd1
   ln fd1 fd2             # لینک دیگری به فایل ما ایجاد می‌کند fd2
   rm fd1                 # تحت تأثیر قرار نمی‌گیرد fd2 حذف می‌شود اما لینک fd1 لینک‎

   # "some_real_file":در این نقطه ما بازهم یک فایل با دو لینک داریم‎
   #  "fd2"و

یا مانند پیوندهای نمادین -- اما با این قیاس باید محتاط باشیم.

   touch some_real_file
   ln -s some_real_file fd1    # را پیوند نمادین از فایل ما می‌سازد fd1‎
   ln -s "$(readlink fd1)" fd2 # را به همان فایلی پیوند نمادین  می‌سازد که fd2 ‎
                               # .به آن لینک نمادین است‎ fd1
   rm fd1                      # .دست نخورده می‌ماند fd2 را حذف می‌کند اما fd1‎

   # .را لازم دارد "readlink" برنامه غیر استاندارد‎
   # :نتیجه عبارت است از‎

   lrwxrwxrwx 1 wooledg wooledg 14 Mar 25 09:19 fd2 -> some_real_file
   -rw-r--r-- 1 wooledg wooledg  0 Mar 25 09:19 some_real_file

   # را استفاده کنیم، به طور ‎"ln -s fd1 fd2"‎ اگر ما سعی می‌کردیم در این مقایسه‎
   #    ها نیست، بلکه چگونگی تصورFD نامساعدی شکست می‌خوردیم. این چگونگی کارکرد‎
   #                    .برخی افراد در باره کار آنها می‌باشد. و این اشتباه است‎

مقایسه‌های دیگر، از جمله تخیل FDها به منزله شیلنگ‌ها. با در نظر گرفتن فایلها به عنوان بشکه‌های پُر آب(یا خالی، یا نیمه پُر). شما می‌توانید شیلنگ را در بشکه قرار بدهید، برای آنکه آب بیشتری در آن انباشته شود. می‌توانید دو شیلنگ را در یک بشکه قرار بدهید، و آنها هر دو آب را در همان بشکه می‌ریزند. آنوقت شما می‌توانید یکی از آن شیلنگ‌ها را حذف کنید، و این امر موجب نمی‌شود شیلنگ دیگر کنار برود. آن یکی بازهم آنجاست.


CategoryShell

پرسش و پاسخ 55 (آخرین ویرایش ‎ 2011-08-23 17:34:06 ‎ توسط S010600032d00065e)




به سیاره لینوکس امتیاز دهید

به اين صفحه امتياز دهيد