wget در برابر curl: کدام را برای دانلود و HTTP انتخاب کنیم؟
مقایسه عملی wget و curl برای دانلود بازگشتی، API، هدر، ریدایرکت و اسکریپت — چه زمانی کدام را انتخاب کنید.
Founder & product engineer

هر دو روی تقریباً همهٔ سرورهای لینوکس دیده میشوند و هر دو «چیزی را از شبکه میگیرند»، اما قرارداد ذهنیشان فرق دارد. curl کلاینت انتقال عمومی است که برای حرف زدن دقیق با HTTP/HTTPS، هدر، متد و بدنه طراحی شده؛ wget بیشتر ابزار دانلود و آینهسازی فایل است — با ادامهٔ خودکار، نامگذاری از URL، و در صورت نیاز پیمایش بازگشتی سایت.
انتخاب غلط معمولاً دردناک نیست، ولی در اسکریپت CI، بکاپ، و عیبیابی API تفاوت رفتار ریدایرکت، کد خروج، و پرچمهای پیشفرض خودش را نشان میدهد. این مقاله بعد از آموزش curl میآید تا مرزها را روشن کند.

پاسخ کوتاه
برای تست API، ارسال JSON، کنترل هدر و دیدن جزئیات پروتکل: curl. برای دانلود یک یا چند فایل با ادامه پس از قطع، ذخیره با نام معقول، و آینهٔ سادهٔ درخت وب: wget. هر دو HTTPS را پشتیبانی میکنند؛ هیچکدام جایگزین مرورگر با موتور JavaScript نیستند. در بسیاری از توزیعها ممکن است فقط یکی از پیش نصب باشد — قبل از اتکا در ایمیج کانتینر مینیمال، وجود باینری را چک کنید.
curl را مثل Postman خط فرمان ببینید؛ wget را مثل دانلودمنیجر قابلاسکریپت.
جدول مقایسهٔ سریع
| معیار | curl | wget |
|---|---|---|
| تمرکز اصلی | کلاینت انتقال / HTTP دقیق | دانلود و بازیابی فایل |
| متد دلخواه (POST/PUT) | عالی با -X و -d | محدودتر؛ تمرکز GET/دانلود |
| ادامهٔ دانلود ناقص | ممکن با -C - | پیشفرض قوی با -c |
| دانلود بازگشتی | خیر (ابزار دیگر) | بله با -r / -m |
| خروجی به stdout | پیشفرض طبیعی | بیشتر به فایل؛ -O - برای stdout |
| پیشرفت در ترمینال | نوار پیشرفت (بدون -s) | نوار/نقطه؛ مناسب دانلود بلند |
| کد خروج و HTTP error | با -f سختگیرتر | سیاست جدا؛ مستند نسخه را ببینید |
دانلود یک فایل
هر دو کار را انجام میدهند، ولی پیشفرض نام فایل و خروجی فرق دارد:
bash
curl -L -o package.tar.gz https://example.com/package.tar.gz curl -L -O https://example.com/package.tar.gz wget https://example.com/package.tar.gz wget -O package.tar.gz https://example.com/package.tar.gz
در curl بدون -o یا -O بدنه روی stdout میآید — عالی برای لوله به jq، خطرناک اگر باینری بزرگ را در ترمینال بریزید. wget بهطور پیشفرض در فایل ذخیره میکند. -L در curl ریدایرکت را دنبال میکند؛ wget معمولاً ریدایرکت را دنبال میکند مگر خلافش را بخواهید.
ادامه پس از قطع شبکه
bash
wget -c https://example.com/big.iso curl -C - -O https://example.com/big.iso
برای ایزو، بکاپ و آرتیفکت بزرگ، این الگو ضروری است. سرور باید Range را بپذیرد؛ وگرنه از صفر شروع میشود. قبل از اتکا در شب ناپایدار، یک بار با فایل کوچک رفتار سرور را بیازمایید.
curl برای API؛ جایی که wget جا میماند
bash
curl -sS -X POST https://api.example.com/v1/items \ -H 'Content-Type: application/json' \ -H "Authorization: Bearer ${TOKEN}" \ -d '{"name":"demo"}'
ساخت هدر سفارشی، متد غیر GET، و بدنهٔ JSON در curl روزمره است. wget میتواند بعضی هدرها را با --header بفرستد و حتی POST کند، ولی قرارداد و مثالهای اکوسیستم API روی curl جمع شدهاند. اگر کار شما تست قرارداد HTTP است، همان مسیر مقالهٔ curl را بروید.
wget برای آینه و بازگشتی
bash
wget -r -np -nk -E https://example.com/docs/ wget -m --wait=1 --limit-rate=200k https://example.com/mirror/
-r بازگشتی، -np جلوگیری از بالا رفتن از مسیر والد، -m آینه با timestamping و مناسب آرشیو سبک. این قابلیت در curl وجود ندارد؛ برای کراول جدیتر ابزارهای تخصصیتر یا اسکریپت خودتان لازم است. احترام به robots.txt و بار سرور را جدی بگیرید — آینهٔ بیادب میتواند IP شما را مسدود کند.
هدر، فقط وضعیت، و سکوت
bash
curl -sS -I https://example.com/ curl -sS -o /dev/null -w '%{http_code}\n' https://example.com/ wget --spider -S https://example.com/ 2>&1 | head
curl -I درخواست HEAD میفرستد. wget --spider بدون دانلود کامل «میزند» و برای چک لینک در اسکریپتهای قدیمی رایج است. برای مانیتورینگ health دقیقتر، الگوی curl با -w و کد وضعیت خواناتر است.
TLS، گواهی، و پروکسی
هر دو به ذخیرهٔ CA سیستم وابستهاند. دور زدن بررسی گواهی (curl -k یا معادل wget) فقط برای آزمایش کنترلشده؛ در production مشکل گواهی را درست کنید. متغیرهای http_proxy/https_proxy روی هر دو اثر میگذارند؛ در عیبیابی سازمانی اول محیط را ببینید.
bash
env | grep -i proxy curl -sS -x http://proxy.example.com:8080 https://example.com/ wget -e use_proxy=yes -e http_proxy=http://proxy.example.com:8080 https://example.com/
کد خروج و شکست خاموش
اشتباه رایج در CI: فرمان «موفق» است چون انتقال TCP تمام شده، در حالی که سرور 404 یا 500 داده. در curl، -f یا خواندن http_code با -w این فاصله را میبندد. در wget نیز باید مستند نسخه و پرچمهای مربوط به وضعیت HTTP را برای اسکریپت خودتان صریح کنید؛ فرض نکنید رفتار با حس شما یکی است.
bash
curl -sS -f -o /dev/null https://example.com/health || exit 1 wget -q --spider https://example.com/health || exit 1
کانتینر و ایمیج مینیمال
ایمژهای distroless یا alpine خیلی لاغر ممکن است هیچکدام را نداشته باشند، یا فقط wget BusyBox با پرچمهای محدود. قبل از کپی کردن دستور از بلاگ، در Dockerfile یا entrypoint وجود باینری را تأیید کنید. برای healthcheck رسمی کانتینر، گاهی wget BusyBox و گاهی curl؛ قرارداد ایمیج پایه را بخوانید نه عادت لپتاپ را.
چه زمانی صریحاً wget؟
- دانلود آرتیفکت بزرگ با احتمال قطعی و نیاز به -c.
- آینهٔ مستندات استاتیک یا درخت فایل با -r/-m.
- اسکریپتهای قدیمی که از قبل روی wget نوشته شدهاند و هزینهٔ بازنویسی بالاست.
- وقتی خروجی پیشفرض-به-فایل خواناتر از مدیریت -o در curl است.
چه زمانی صریحاً curl؟
- هر کار API: JSON، Bearer، فرم، آپلود چندبخشی.
- عیبیابی TLS و زمانبندی با -v و -w.
- لولهٔ stdout به jq، grep، یا ابزار بعدی.
- نیاز به متد و هدر دقیق همتراز کلاینت اپ.
اشتباههای رایج
- ریختن خروجی باینری curl بدون -o در ترمینال و بههمریختن نشست.
- فراموش -L در curl پشت CDN که ۳۰۱ میدهد.
- آینهٔ wget بدون rate limit روی سایت دیگران.
- سختکد کردن توکن در تاریخچهٔ هر دو ابزار.
- فرض یکسان بودن رفتار ریدایرکت و کد خروج در همهٔ نسخهها.
نمونهٔ تصمیم در عمل
- نیاز به POST JSON دارید؟ curl.
- باید iso پنجگیگابایتی را امشب تمام کنید و لینک ضعیف است؟ wget -c (یا curl -C -).
- میخواهید پاسخ را به jq بدهید؟ curl -sS.
- میخواهید پوشهٔ docs را محلی آرشیو کنید؟ wget -m با ادب شبکه.
اگر تیم روی یکی استاندارد شده، مگر دلیل قوی، دومی را قاطی نکنید؛ هزینهٔ ذهنی دو قرارداد بیشتر از سود جزئی پرچمهاست.
ارتباط با ابزارهای دیگر
برای انتقال فایل بین سرورها هنوز scp/rsync/sftp جایگاه خود را دارند؛ wget/curl جایگزین بکاپ بلاکدستگاهی نیستند. برای تست قرارداد پیچیده، مجموعههای تست HTTP مکملاند؛ curl نقطهٔ شروع سریع پس از deploy میماند.
رفتار ریدایرکت با جزئیات بیشتر
ریدایرکت جایی است که حس «هر دو یکیاند» میشکند. curl بدون -L بدنهٔ صفحهٔ میانی را میدهد و دنبال Location نمیرود؛ بسیاری CDNها اول ۳۰۱/۳۰۲ میدهند. wget بهطور پیشفرض دنبال میکند. اگر اسکریپت مهاجرت URL مینویسید، رفتار را صریح کنید نه ضمنی.
bash
curl -sS -D - -o /dev/null https://example.com/old | head curl -sS -L -o /dev/null -w '%{url_effective} %{http_code}\n' https://example.com/old wget -S -O /dev/null https://example.com/old 2>&1 | head
مراقب تغییر متد هنگام ریدایرکت باشید: بعضی ۳۰۲ها POST را به GET تبدیل میکنند. برای APIهای حساس، URL نهایی را از قبل بدانید و از زنجیرهٔ طولانی در production اجتناب کنید.
نام فایل، محتوا و Content-Disposition
وقتی سرور نام فایل را در هدر Content-Disposition میفرستد، ابزارها ممکن است متفاوت عمل کنند. برای آرتیفکتهای نسخهدار بهتر است نام را خودتان با -o/-O ثابت کنید تا مسیر اسکریپت شکننده نشود.
bash
curl -sS -D - -o artifact.bin https://example.com/download/latest 2>&1 | grep -i content-disposition wget --content-disposition https://example.com/download/latest
در اتوماسیون، نام ثابت بههمراه checksum جداگانه قابل اعتمادتر از حدس نام از URL است.
محدودیت نرخ و ادب شبکه
bash
wget --limit-rate=500k -c https://example.com/big.iso curl --limit-rate 500k -C - -O https://example.com/big.iso
روی لینک اشتراکی یا سرور مشترک، بدون سقف ممکن است بقیهٔ کارها را خفه کنید. برای آینه، --wait بین درخواستها در wget هم مفید است. این موضوع اخلاق عملیاتی است نه فقط بهینهسازی.
احراز هویت پایه و هدر سفارشی در هر دو
bash
curl -sS -u 'user:pass' https://example.com/private/file wget --user=user --password=pass https://example.com/private/file curl -sS -H 'Authorization: Bearer ${TOKEN}' -O https://example.com/private/file wget --header='Authorization: Bearer ${TOKEN}' https://example.com/private/file
رمز در argv به فرایندهای دیگر دیده میشود؛ ترجیح متغیر محیطی، فایل مجوزدار، یا netrc با دسترسی محدود. هرگز توکن را در README عمومی نمونه نگذارید.
چکسام و تأیید یکپارچگی پس از دانلود
دانلود موفق بهمعنای فایل درست نیست. الگوی حرفهای: گرفتن آرتیفکت، سپس مقایسه با checksum منتشرشده.
bash
curl -sS -L -o app.tgz https://example.com/app.tgz curl -sS -L -o app.tgz.sha256 https://example.com/app.tgz.sha256 sha256sum -c app.tgz.sha256
همین کار با wget یکسان است؛ تفاوت ابزار در مرحلهٔ تأیید معنا ندارد. در CI این مرحله را اجباری کنید.
سناریو: انتخاب در Dockerfile
در مرحلهٔ build اغلب فقط یک فایل لازم است. مثال با curl:
bash
RUN curl -fsSL -o /tmp/tool.tgz https://example.com/tool.tgz \ && tar -xzf /tmp/tool.tgz -C /usr/local \ && rm /tmp/tool.tgz
-f شکست HTTP را جدی میگیرد، -sS برای لاگ تمیزتر، -L برای ریدایرکت. اگر پایهٔ ایمیج فقط wget BusyBox دارد، همان را با پرچمهای موجود بازنویسی کنید و در مستند ایمیج یادداشت بگذارید.
چکلیست انتخاب در تیم
اگر استاندارد تیم مشخص نیست، یک صفحهٔ کوتاه داخلی بنویسید: API و عیبیابی HTTP با curl؛ آرتیفکت و آینه با wget. استثناها را با دلیل ثبت کنید تا هر PR یک ابزار تصادفی نیاورد. یکسانسازی از بحث «کدام سریعتر است» مفیدتر است.
در code review، به جای سلیقه، به رفتار نگاه کنید: آیا ریدایرکت صریح است؟ آیا شکست HTTP دیده میشود؟ آیا توکن در لاگ نمیافتد؟ این سوالها مستقل از نام باینریاند.
برای آموزش نیروی جدید، همان دو سناریوی ثابت را تمرین بدهید: یک GET JSON با کد وضعیت، و یک دانلود قابلادامه. مهارت انتقالپذیر مهمتر از حفظ همهٔ پرچمهاست.
محدودیت پروتکل و انتظار واقعی
هیچکدام موتور رندر صفحهٔ مدرن نیستند. اگر API پشت چالش مرورگر یا جریان چندمرحلهٔ کوکی پیچیده است، ابزار تخصصیتر یا تست در لایهٔ اپ لازم میشود. wget/curl لایهٔ انتقال را شفاف میکنند نه رفتار کامل کلاینت وب را.
برای پروتکلهای غیر HTTP نیز curl گسترده است؛ wget عمدتاً روی HTTP(S)/FTP کلاسیک میماند. قبل از اجبار ابزار، پروتکل واقعی را مشخص کنید.
نمونهٔ مقایسهٔ عملی در یک بعدازظهر
فرض کنید باید هم سلامت API را چک کنید هم بستهٔ نصب را از آینه بگیرید. مسیر سالم این است که دو فرمان جدا با ابزار مناسب بنویسید نه اینکه یکی را به زور برای هر دو خم کنید. برای سلامت:
bash
curl -sS -o /dev/null -w '%{http_code} %{time_total}\n' --max-time 5 https://api.example.com/health
برای بسته:
bash
wget -c --timeout=20 --tries=3 -O /tmp/tool.tgz https://downloads.example.com/tool.tgz
سپس checksum. اگر هر دو را با یک ابزار انجام دهید هم ممکن است کار کند؛ جدا کردن مسئولیتها خوانایی runbook را بالا میبرد و وقتی یکی شکست بخورد علت روشنتر است.
در بازبینی پس از حادثه، همین تفکیک کمک میکند بفهمید مشکل از لایهٔ HTTP API بوده یا از پایداری دانلود آرتیفکت — دو کلاس خطای متفاوت با مالکان متفاوت.
خلاصه
wget و curl رقیب مطلق نیستند؛ دو قرارداد متفاوت روی مسئلهٔ «گرفتن داده از شبکه»اند. curl را برای گفتوگوی دقیق HTTP و اسکریپت API انتخاب کنید؛ wget را برای دانلود مقاوم و آینه. در هر دو، ریدایرکت، گواهی، پروکسی و کد شکست HTTP را صریح کنید تا CI سبزِ دروغین نسازد.
سوالات متداول
آیا یکی سریعتر است؟
برای یک GET ساده تفاوت عملی معمولاً ناچیز است؛ گلوگاه شبکه، دیسک و سرور است نه انتخاب بین این دو. بهینهسازی زودرس اینجا بیفایده است.
در اسکریپت شل کدام قابلحملتر است؟
بستگی به ایمیج دارد. خیلی از CIهای لینوکسی هر دو را دارند؛ کانتینرهای مینیمال را جدا بررسی کنید. اگر باید یکی را نصب کنید، بر اساس غالبِ کار تیم انتخاب کنید نه سلیقهٔ شخصی.
میتوانم فقط با wget API را تست کنم؟
برای GET ساده بله؛ برای جریان واقعی توسعهٔ API معمولاً درد بیشتر از سود است. همان curl.
منابع و مراجع
- GNU Wget — Overview: https://www.gnu.org/software/wget/
- GNU Wget Manual: https://www.gnu.org/software/wget/manual/wget.html
- curl — command line tool: https://curl.se/
- curl man page: https://curl.se/docs/manpage.html
- wget(1) Linux man page (man7): https://man7.org/linux/man-pages/man1/wget.1.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.




