
اگر از یک کاربر ویندوز بخواهید سطح شارژ باتری لپتاپ را از خط فرمان (Command Line) بررسی کند، احتمالاً از یک cmdlet در PowerShell یا گزارش باتری استفاده میکند. اما کاربر لینوکس احتمالاً همان مقدار را مستقیماً از یک فایل میخواند. در لینوکس تقریباً همهچیز یک فایل است و این ویژگی از تصمیمی طراحی در آزمایشگاههای بل (Bell Labs) در بیش از ۵۰ سال پیش سرچشمه میگیرد. لینوکس آن را از یونیکس (Unix) به ارث برده و یکی از مشخصههای تعیینکنندهای است که آن را از ویندوز جدا میکند.
«همهچیز یک فایل است» در لینوکس به چه معناست؟
یونیکس از سال ۱۹۶۹ در آزمایشگاههای بل شکل گرفت و سیستم فایل (File System) از همان ابتدا در قلب طراحی آن قرار داشت. دنیس ریچی (Dennis Ritchie) بعدها ایده فایلهای دستگاه (Device Files) را به خود نسبت داد و حتی نخستین نسخههای یونیکس فایلهای ویژهای برای نمایش سختافزار داشتند؛ چیزی شبیه به آنچه امروز لینوکس استفاده میکند. ریچی و کن تامپسون (Ken Thompson) در مقاله سال ۱۹۷۴ خود سه نوع فایل را برشمردند: فایلهای معمولی، پوشهها و فایلهای ویژه برای دستگاههای ورودی/خروجی (I/O Devices).
این طراحی یک رابط کوچک و یکپارچه فراهم میکرد و در مقایسه با گزینههای آن زمان کار را بسیار سادهتر میساخت. یک برنامه میتواند چیزی را باز کند، از آن بخواند، در آن بنویسد و آن را ببندد، بدون اینکه اهمیت داشته باشد آن چیز یک سند، ترمینال، دیسک یا حتی برنامهای دیگر است. یونیکس همچنین ساختاری را به محتوای فایل تحمیل نمیکرد. فایل دنبالهای از بایتها (Bytes) در نظر گرفته میشد و تصمیم درباره ماهیت آن بر عهده برنامهای بود که آن بایتها را میخواند.
این رویکرد در مقایسه با ویندوز تفاوت مهمی دارد. ویندوز NT حول اشیای هسته (Kernel Objects) ساخته شده که مدیر اشیاء (Object Manager) آنها را ردیابی میکند و فضای نام (Namespace) سلسلهمراتبی خود را با مسیرهایی مانند \Device\HarddiskVolume1 نگه میدارد. برنامهها به این اشیا از طریق دستگیرهها (Handles) دسترسی پیدا میکنند، تقریباً همانطور که برنامههای یونیکس از توصیفگرهای فایل (File Descriptors) استفاده میکنند؛ اما تفاوت در قابلیت مشاهده است. این فضای نام در ویندوز بیرون از سیستم فایل قرار دارد، در حالی که در یونیکس دقیقاً داخل درخت پوشهها جای میگیرد.
سختافزار در /dev بهصورت فایل دیده میشود
/dev ملموسترین نمونه امروزی از برخورد با سختافزار بهعنوان فایل در لینوکس است. یک درایو SATA به شکل چیزی مانند /dev/sda ظاهر میشود، یک درایو NVMe به شکل /dev/nvme0n1 و پارتیشنها هم در کنار آنها ورودی جداگانه خود را دارند. برخی ورودیها هیچ سختافزاری پشت خود ندارند: /dev/null هر چیزی را که در آن نوشته شود دور میریزد، /dev/zero صفرهای بیپایان تولید میکند و /dev/urandom بایتهای تصادفی میسازد؛ همه اینها در سناریوهای مختلف کاربرد دارند.
و چون دیسک مانند یک فایل معمولی رفتار میکند، ابزارهای معمولی هم روی آن کار میکنند. dd نمونه خوبی است؛ یک ابزار کپی همهمنظوره که اگر یک ISO را بهعنوان ورودی و /dev/sdX را بهعنوان خروجی به آن بدهید، یک درایو USB قابل بوت ساختهاید. اگر به اشتباه درایو دیگری را وارد کنید، همان دیسک با محتوای ISO بازنویسی میشود. این روی دیگر یک رابط بسیار یکدست است و دلیل وجود ابزارهای اختصاصی هم همین است؛ در ویندوز کافی است از چیزی مانند Rufus استفاده کنید.
هسته از طریق /proc و /sys پاسخ میدهد
یکی از جنبههای جالبتر برخورد با همهچیز بهعنوان فایل، از سمت هسته (Kernel) میآید؛ هسته لینوکس بخشی از وضعیت خود را در قالب فایل نمایش میدهد. این کار از طریق سیستمهای فایل مجازی (Virtual File Systems) انجام میشود که روی دیسک وجود ندارند و فقط هنگام خواندن تولید میشوند.
/proc نخستین نمونه است: تام کیلیان (Tom Killian) آن را برای یونیکس ساخت و در مقالهای در سال ۱۹۸۴ با عنوان «Processes as Files» معرفی کرد. لینوکس سپس /proc خود را در سال ۱۹۹۲ افزود و خیلی زود آن را فراتر از فرایندها گسترش داد؛ به همین دلیل دستورهایی مانند cat /proc/cpuinfo و cat /proc/meminfo روشهای رایجی برای بررسی مشخصات سختافزار و حافظه هستند.
/sys کمی دیرتر در لینوکس ۲.۶ آمد و مدل دستگاههای هسته را به شکل درختی از فایلهای کوچک نمایش داد. برای مثال، سطح شارژ باتری لپتاپ در فایلی مانند /sys/class/power_supply/BAT0/capacity بهصورت یک درصد ساده قرار دارد. حسگرهای حرارتی را هم میتوان از فایلهایی مانند /sys/class/thermal/thermal_zone0/temp بر حسب میلیدرجه سلسیوس بررسی کرد؛ بنابراین مقدار ۴۵۰۰۰ یعنی ۴۵ درجه. بسیاری از این فایلها قابل نوشتن هستند و میتوانند رفتار هسته را تغییر دهند.
چرا این طراحی لینوکس را متمایز میکند
وقتی سختافزار و وضعیت هسته به جریانهای بایت تبدیل شوند، ابزارهای ساختهشده روی آنها میتوانند کاملاً متفاوت عمل کنند و این به سود کاربر است. هر برنامه در لینوکس با سه توصیفگر فایل استاندارد شروع میکند: ورودی، خروجی و خطا؛ و همین سه مورد در استفاده از خط فرمان نقشی کلیدی دارند. در اوایل سال ۱۹۷۳ خط لولهها (Pipes) به ویرایش سوم یونیکس اضافه شدند و این اتفاق بزرگی بود.
خط لولهها اجازه میدهند خروجی یک برنامه مستقیماً به ورودی برنامهای دیگر برود؛ به همین شکل کاربران لینوکس میتوانند ابزارهای کوچکی مانند grep، sort و awk را زنجیرهوار به هم وصل کنند، بهجای اینکه یک برنامه بزرگ را باز کنند. این کار بسیاری از جریانهای کاری خط فرمان را ممکن میسازد. توانایی گرفتن خروجی خطای یک برنامه با grep و هدایت آن به یک فایل گزارش در یک خط، چیزی است که بسیاری از کاربران لینوکس تقریباً هر بار برای عیبیابی از آن استفاده میکنند.
PowerShell در ویندوز آگاهانه مسیر دیگری را انتخاب کرده و بهجای متن، اشیای ساختیافته .NET را بین دستورها منتقل میکند. هیچکدام از این دو رویکرد اشتباه نیستند، اما عادتهای بسیار متفاوتی میسازند. برای کسی که عادتهای خط فرمانش با لینوکس شکل گرفته، درک PowerShell واقعاً دشوار است.
ایدهای که همهچیز را تغییر داد
مفهوم «همهچیز یک فایل است» از بیشتر افرادی که امروز به آن تکیه میکنند قدیمیتر است و حتی از خود لینوکس هم قدیمیتر است. بخش بزرگی از آنچه یک سیستمعامل مانند لینوکس را متمایز میکند از همان روزهای نخست یونیکس میآید. البته رابطهایی در لینوکس وجود دارند که فایل نیستند، مانند D-Bus و netlink، اما لایه فایل همچنان در زیر همهچیز باقی میماند. اگر از ویندوز آمدهاید و چیزی در لینوکس برایتان کاملاً روشن نیست، در بیشتر موارد آن «چیز» توسط یک فایل کنترل میشود.