لوله (pipe) در لینوکس: اتصال خروجی یک فرمان به ورودی دیگری
مفهوم pipe، stdout به stdin، تفاوت با ریدایرکت، tee، خطاهای رایج و ساخت خط لولهٔ عیبیابی در لینوکس.
Founder & product engineer

فلسفهٔ یونیکس میگوید ابزارهای کوچک بساز که خوب کار کنند و با هم ترکیب شوند. لوله (pipe) همان ترکیب است: خروجی استاندارد یک فرایند به ورودی استاندارد فرایند بعدی وصل میشود بدون فایل میانی اجباری. نماد | در شل این اتصال را میسازد.
بدون فهم لوله، grep و awk فقط فرمانهای جدا میمانند؛ با لوله، یک جملهٔ عملیاتی میسازید: «فرایندها را ببین، سنگینها را جدا کن، شمارش کن». مقالهٔ بعدی ریدایرکت فایل را پوشش میدهد؛ اینجا تمرکز روی اتصال فرمان به فرمان است.

پاسخ کوتاه
`cmd1 | cmd2` یعنی stdout مربوط به cmd1 به stdin مربوط به cmd2 میرود. stderr بهطور پیشفرض لوله نمیشود مگر آن را جدا ریدایرکت کنید. برای دیدن و ذخیرهٔ همزمان از `tee` استفاده کنید. در اسکریپتهای جدی `set -o pipefail` را در نظر بگیرید تا شکست وسط لوله خاموش نماند. لوله جایگزین همهچیز نیست؛ برای دادهٔ باینری بزرگ یا پروتکل پیچیده گاهی فایل موقت یا ابزار تخصصی بهتر است.
لوله جریان داده است نه جادو؛ اگر سمت چپ چیزی چاپ نکند، سمت راست گرسنه میماند.
stdin، stdout، stderr — حداقل لازم
هر فرایند معمولاً سه توصیفگر دارد: ۰ ورودی، ۱ خروجی، ۲ خطا. فرمانهای فیلترگونه از ۰ میخوانند و به ۱ مینویسند. پیامهای تشخیصی را به ۲ میفرستند تا لولهٔ داده را آلوده نکنند — به همین دلیل `grep` روی خروجی `cmd 2>&1` گاهی لازم است.
bash
ls /no/such 2>&1 | grep -i 'no such' printf 'a\nb\nc\n' | grep b
اولین لولههای مفید
bash
ps aux | head df -h | grep -E '/$|/var' journalctl -n 100 --no-pager | grep -i fail cat access.log | awk '{print $1}' | sort | uniq -c | sort -nr | head
نکته: `cat file | cmd` اغلب معادل `cmd < file` یا خود cmd با آرگومان فایل است؛ ولی عادت لوله برای ترکیب بعدی مانعی ندارد. در نقد سبک، UUOC (useless use of cat) را بشناسید ولی در خوانایی تیم افراط نکنید.
tee: انشعاب جریان
bash
echo 'hello' | tee /tmp/hello.txt command | tee /tmp/full.log | grep -i error command 2>&1 | tee -a /tmp/session.log
tee هم به فایل مینویسد هم به stdout ادامه میدهد. برای جلسهٔ عیبیابی که باید هم ببینید هم آرشیو کنید، طلاست. -a الحاق میکند.
کد خروج و pipefail
بهطور پیشفرض در bash، کد خروج لوله معمولاً وضعیت آخرین فرمان است. اگر `grep` چیزی پیدا نکند با کد ۱ خارج میشود و ممکن است CI را بشکند؛ برعکس، شکست `cmd1` ممکن است دیده نشود اگر آخری موفق باشد.
bash
set -o pipefail false | true; echo $? true | false; echo $?
با pipefail، شکست هر بخش لوله در وضعیت کلی منعکس میشود. در اسکریپت production این را آگاهانه روشن یا برای آن مرحله مدیریت کنید.
بافر و احساس «گیر کردن»
وقتی خروجی لوله دیر ظاهر میشود، گاهی بافر بلوکی stdout مقصر است. ابزارهایی مثل `grep --line-buffered` یا `stdbuf` در سناریوهای زنده کمک میکنند. برای لاگ دنبالشونده:
bash
tail -f app.log | grep --line-buffered -i error
لوله و سوئیچهای تعاملی
فرمانهایی که به TTY وابستهاند پشت لوله رفتار غیرتعاملی میگیرند. مثلاً بعضی ابزارها رنگ یا pager را عوض میکنند. اگر خروجی عجیب شد، اول بپرسید آیا stdin/stdout دیگر ترمینال نیست.
نامگذاری مراحل برای انسان
لولههای خیلی بلند در یک خط برای آیندهخوان سختاند. در اسکریپت، بشکنید یا متغیر:
bash
journalctl -u api -n 2000 --no-pager \ | grep -F 'timeout' \ | awk '{print $6}' \ | sort | uniq -c | sort -nr
هر خط یک مسئولیت. اگر منطق شاخه دارد، بهجای لولهٔ مارپیچ، اسکریپت با فایل موقت خوانا بنویسید.
تفاوت مفهومی با ریدایرکت
| ساز و کار | چه میکند |
|---|---|
| cmd1 | cmd2 | اتصال زندهٔ stdout→stdin بین فرایندها |
| cmd > file | نوشتن stdout در فایل |
| cmd < file | خواندن stdin از فایل |
| cmd >> file | الحاق به فایل |
میتوانید ترکیب کنید: `cmd < in.txt | filter > out.txt`. ترتیب و پرانتز در شلهای مختلف برای ریدایرکت پیچیده را ساده نگه دارید.
xargs در مرز لوله
bash
printf 'a\nb\n' | xargs -I{} echo "item-{}" find . -name '*.log' -print0 | xargs -0 wc -l
لوله داده را به stdin میدهد؛ خیلی فرمانها آرگومان خط فرمان میخواهند نه stdin. xargs پل است. برای نام فایل، null-delimited را فراموش نکنید.
اشتباههای رایج
- فرض اینکه stderr هم لوله میشود.
- نادیده گرفتن pipefail در CI.
- لولههای ۲۰ مرحلهای بدون توضیح.
- grep تعاملی رنگدار که کد ANSI را به مرحلهٔ بعد میریزد.
- استفاده از لوله برای جابهجایی فایلهای عظیم وقتی همان ابزار فایل را مستقیم میخواند.
الگوی عیبیابی سرور با لوله
- منبع خام: journalctl/ps/ss.
- فیلتر: grep -F یا -E.
- برش: awk/cut.
- تجمیع: sort | uniq -c | sort -nr.
- ثبت: tee به فایل تیکت.
bash
ss -tnp | tee /tmp/ss.txt | grep ':443'
لوله در مقابل فایل موقت
مزیت لوله: بدون مدیریت پاکسازی فایل، موازیسازی طبیعی فرایندها. مزیت فایل موقت: بازرسی میانی، اجرای مجدد از وسط، ابزارهایی که دو بار روی ورودی seek میکنند. وقتی باید خروجی میانی را نگه دارید، از tee یا فایل استفاده کنید نه اینکه لوله را حفظ کنید به زور.
FIFO و لولهٔ نامدار
bash
mkfifo /tmp/myfifo # در یک ترمینال: # cat /tmp/myfifo # در دیگری: # echo hello > /tmp/myfifo
لولهٔ نامدار برای اتصال فرایندهایی که پدر مشترک شل | ندارند مفید است؛ در کار روزمرهٔ ادمین کمتر از | دیده میشود ولی مفهوم همان جریان است.
مرجع هسته: pipe(7) رفتار لوله و ظرفیت بافر را توضیح میدهد.
لوله و سیگنالها
وقتی با Ctrl-C لوله را قطع میکنید، سیگنال معمولاً به گروه فرایند میرسد. در اسکریپتهای بلند، رفتار پاکسازی (trap) را صریح کنید تا فایل نیمهکاره رها نشود. برای جاب پسزمینه، مدیریت job شل را با لوله قاطی نکنید مگر مسلط باشید.
اندازهٔ بافر لوله و فشار برگشتی
اگر مصرفکننده کند باشد، تولیدکننده وقتی بافر لوله پر شد بلوکه میشود — این فشار برگشتی طبیعی است و گاهی بهتر از پر شدن دیسک با فایل موقت غولآساست. اگر هر دو طرف باید مستقل پیش بروند، صف یا فایل میانی آگاهانه طراحی کنید.
جزئیات ظرفیت در pipe(7) آمده است؛ برای کار روزمره کافی است بدانید لوله حافظهٔ بینهایت ندارد.
خوانایی در مستند عملیات
لولهای که در runbook میگذارید باید با دادهٔ نمونه در همان صفحه قابل بازتولید باشد. اگر به مسیر میزبان خاص وابسته است، آن را پارامتر کنید. runbook بدون خروجی نمونه فقط حس امنیت میدهد.
لوله در اسکریپتهای نظارتی
برای جمعآوری شواهد در حادثه، لوله را با tee به پروندهٔ زماندار وصل کنید تا بعداً در تیکت پیوست شود. نام فایل را با timestamp بسازید تا بازنویسی نشود.
bash
stamp=$(date +%Y%m%dT%H%M%S) ps aux | tee "/tmp/ps-${stamp}.txt" | head ss -tnp | tee "/tmp/ss-${stamp}.txt" | head
این عادت ساده اختلاف روایت «من دیدم» را کم میکند. پروندهها را پس از بستن حادثه طبق سیاست نگهداری پاک یا آرشیو کنید.
اگر داده حساس در خروجی است، دسترسی دایرکتوری /tmp تیمی را جدی بگیرید یا مستقیم به مسیر با مجوز محدود بنویسید.
خلاصه
لوله ستون فقرات ترکیب ابزارهای یونیکس است: stdout را به stdin بعدی وصل کنید، stderr را آگاهانه مدیریت کنید، با tee انشعاب بگیرید، و در اسکریپت pipefail را بشناسید. لولههای خوانا بهتر از یکخطیهای قهرمانانه نگهداری میشوند.
سوالات متداول
چند فرمان میتوان در یک لوله آورد؟
از نظر شل محدود سخت عملی معمولاً خوانایی است نه سقف تکنیکی. وقتی از حدود درک خارج شد، بشکنید.
چرا خروجی ناقص است؟
بافر، فرمان قبلی هنوز ننوشته، یا فیلتر خیلی تنگ. بدون فیلتر وسطی را با tee ببینید.
آیا | در همهٔ شلها یکی است؟
ایده یکی است؛ جزئیات pipefail و آخرین وضعیت به شل وابسته است. bash و zsh را جدا در مستند اسکریپت قید کنید.
منابع و مراجع
- Bash Reference Manual — Pipelines: https://www.gnu.org/software/bash/manual/html_node/Pipelines.html
- pipe(7) — Linux manual page: https://man7.org/linux/man-pages/man7/pipe.7.html
- tee(1): https://man7.org/linux/man-pages/man1/tee.1.html
- Bash pipefail (Bash FAQ / manual set options): https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html
Author
Soheil Ebrahimpour is the founder of FutureForge. He works on product design, architecture, and getting custom software into production.
Related notes
If you are unsure about architecture or the build path, we can talk about the project.
Describe the problem and the constraints. If there is a fit, we will schedule a conversation.




