تغ

تغییر مسیر در Bash

{one: "۱ تمرین", other: "%{count} تمرین"}

درباره‌ی تغییر مسیر

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

  1. ورودی استاندارد (stdin): جایی که برنامه ورودی خود را دریافت می‌کند (معمولاً از صفحه‌کلید).
  2. خروجی استاندارد (stdout): جایی که برنامه خروجی معمول خود را می‌فرستد (معمولاً به صفحه‌ی ترمینال).
  3. خطای استاندارد (stderr): جایی که برنامه پیام‌های خطا را می‌فرستد (معمولاً به صفحه‌ی ترمینال).

به یاد بیاورید که این‌ها را در فصل خط لوله و فهرست‌های دستور معرفی کردیم.

Note

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

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

عملگرهای اصلی تغییر مسیر

در ادامه رایج‌ترین عملگرهای تغییر مسیر و کاری که انجام می‌دهند آمده است:

> (تغییر مسیر خروجی)

  • هدف: تغییر مسیر خروجی استاندارد (stdout) یک دستور به یک فایل.

  • رفتار:

    • اگر فایل وجود نداشته باشد، ساخته می‌شود.
    • اگر فایل وجود داشته باشد، محتوای آن بازنویسی می‌شود.
  • مثال:

    # Sends the output of 'ls -l' to 'file_listing.txt'
    ls -l > file_listing.txt
    
Caution

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

date > date.txt         # populate the file with the current date
cat date.txt > date.txt # 'date.txt' is now empty!

در دستور دوم مثال بالا،

  1. ابتدا Bash فایلی را که در تغییر مسیر نام برده شده کوتاه می‌کند. این کار محتوای قبلی را از بین می‌برد و فایلی خالی برجای می‌گذارد.
  2. سپس Bash فایل تازه خالی‌شده را می‌خواند.
  3. سپس Bash محتوا (یعنی هیچ چیز) را دوباره در فایل می‌نویسد.

>> (تغییر مسیر خروجی با افزودن)

  • هدف: افزودن خروجی استاندارد (stdout) یک دستور به یک فایل.

  • رفتار:

    • اگر فایل وجود نداشته باشد، ساخته می‌شود.
    • اگر فایل وجود داشته باشد، خروجی به انتهای فایل اضافه می‌شود.
  • مثال:

    # Adds "Another line" to the end of the file
    echo "Another line" >> file_listing.txt
    

< (تغییر مسیر ورودی)

  • هدف: تغییر مسیر ورودی استاندارد (stdin) یک دستور از یک فایل.

  • رفتار: دستور ورودی خود را به‌جای صفحه‌کلید از فایل مشخص‌شده می‌خواند.

  • مثال:

    # 'tr' reads from 'lowercase.txt' and
    # output is redirected to 'uppercase.txt'
    tr 'a-z' 'A-Z' < lowercase.txt > uppercase.txt
    

2> (تغییر مسیر خطا):

  • هدف: تغییر مسیر خطای استاندارد (stderr) یک دستور به یک فایل.
  • رفتار: پیام‌های خطا به‌جای ترمینال به فایل مشخص‌شده فرستاده می‌شوند.
  • مثال:
    # Error message from 'rm' is sent to 'error_log.txt'
    rm non_existent_file 2> error_log.txt
    

می‌توانید خطای استاندارد را با 2>> به یک فایل بیفزایید.

تغییر مسیرهای دیگر

تغییر مسیرهایی هم وجود دارند که می‌توانند stdin و stderr را با هم ادغام کنند. برای جزئیات به راهنما مراجعه کنید.

/dev/null

/dev/null یک فایل ویژه است که

  • وقتی از آن می‌خوانید، فایلی خالی است و
  • همه‌ی داده‌ای که در آن نوشته می‌شود را دور می‌ریزد.

گاهی آن را «سبد بیت» می‌نامند. برای جلوگیری از نمایش خروجی یا خطاها مفید است.

some_command > /dev/null  # Discards stdout
some_command 2> /dev/null # Discards stderr

# Using /dev/null as input will prevent the command
# from reading data from the keyboard
some_command < /dev/null

ترکیب تغییر مسیرها

می‌توان چندین تغییر مسیر را همزمان نوشت.

some_command < input.txt > output.txt 2> error.txt

می‌توان یک تغییر مسیر را کپی کرد.

# send stderr to the same destination as stdout
some_command > output.txt 2>&1

وقتی 2>&1 را می‌بینید، آن را این‌طور بخوانید: «خطای استاندارد را به هر جایی که خروجی استاندارد همین حالا به آن اشاره می‌کند تغییر مسیر بده». Bash دستورهای تغییر مسیر را دقیقاً از چپ به راست پردازش می‌کند، یعنی می‌توانید این کار را بکنید:

# redirect stdout to 'output1.txt'
# redirect stderr to the same place
# then change stdout to 'output2.txt'
some_command > output1.txt 2>&1 > output2.txt
Advanced

توصیف‌گرهای فایل

در بستر برنامه‌نویسی شل و سیستم‌عامل‌هایی مانند Linux/Unix، توصیف‌گر فایل (FD) یک عدد صحیح نامنفی است که به‌عنوان شناسه یا دستگیره‌ای برای یک فایل باز یا منبع ورودی/خروجی (I/O) عمل می‌کند. آن را مانند یک برچسب یا شماره‌ی مرجع در نظر بگیرید که سیستم‌عامل برای پیگیری فایل‌های باز و جریان‌های داده از آن استفاده می‌کند.

شماره‌هایی که در سمت چپ تغییر مسیرها می‌بینید، توصیف‌گرهای فایل هستند.

به جریان‌های ورودی/خروجی استاندارد، سه توصیف‌گر فایل نخست اختصاص داده می‌شود:

  • ورودی استاندارد، FD ۰ است
  • خروجی استاندارد، FD ۱ است
  • خطای استاندارد، FD ۲ است

توصیف‌گرهای فایل تازه را می‌توان با دستور exec و عملگرهای تغییر مسیر تعیین یا ایجاد کرد.

# create FD 3 as a copy of stdout
exec 3>&1
# send stdout to a log file
exec > log.txt

# then redirect both stdout and file descriptor 3
echo "some debug message" >&3  # displayed in the terminal
some_command  2>&1 # stdout and stderr send to 'log.txt'

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

خلاصه

چرا تغییر مسیر مفید است؟

  • ذخیره‌ی خروجی: نتایج یک دستور را برای بررسی یا پردازش بعدی ذخیره کنید.
  • ثبت وقایع: پیام‌های خطا را برای debug کردن بگیرید.
  • خودکارسازی: دستورها را به هم زنجیر کنید و از خروجی یکی به‌عنوان ورودی دیگری استفاده کنید.
  • پالایش: خروجی ناخواسته را دور بریزید.
  • پردازش دسته‌ای: داده را به‌جای تایپ دستی، از فایل‌ها پردازش کنید.
  • اسکریپت‌نویسی: تغییر مسیرها برای نوشتن اسکریپت‌های شل مقاوم ضروری است.

تغییر مسیرهای شل کنترل دقیقی بر نحوه‌ی تعامل برنامه‌ها با داده به شما می‌دهد و به شما امکان می‌دهد گردش‌کارهای پیچیده بسازید و اطلاعات را به‌طور مؤثر مدیریت کنید.

ویرایش از طریق GitHub این پیوند در پنجره یا زبانه‌ی جدیدی باز می‌شود