رفع خطای unknown terminal type در SSH بدون دسترسی root
اگر با خطای unknown terminal type در SSH مواجه شدید، به دلیل عدم شناسایی نام ترمینال در دیتابیس سرور است. با کامپایل کردن فایل terminfo در دایرکتوری خانگی مشکل را حل کنید.
معنای خطای "unknown terminal type"
خطای unknown terminal type در هنگام اتصال SSH به این معناست که نام موجود در TERM هیچ ورودی منطبقی در دیتابیس terminfo روی سرور ندارد. شبیهساز ترمینال شما این نام را روی لپتاپتان تنظیم میکند، اما دیتابیسی که باید آن را شناسایی کند، روی ماشین مقصد قرار دارد. زمانی که جستجو با شکست مواجه میشود، تمام برنامههای مبتنی بر curses روی آن سرور پیش از ترسیم هر چیزی متوقف میشوند، زیرا هیچ توصیفی از قابلیتهای ترمینال شما در اختیار ندارند.
راهکاری که تمام ویژگیهای شبیهساز شما را حفظ میکند، تنها یک دستور است: ورودی terminfo خود را در ~/.terminfo روی سرور کامپایل کنید. کتابخانه ncurses پیش از هر دایرکتوری سیستمی، دایرکتوری خانگی شما را جستجو میکند (تنها متغیر $TERMINFO، در صورت تنظیم بودن، زودتر بررسی میشود)، بنابراین این کار نیازی به دسترسی root ندارد و هیچ تغییری برای سایر کاربران ایجاد نمیکند.
TERM یک نام است و terminfo پایگاهداده آن
TERM یک رشته را در خود نگه میدارد و آن رشته فقط یک کلید است. terminfo یک پایگاهداده کامپایلشده از توصیفات ترمینال است و این کلید، روشی است که برنامه برای یافتن توصیف مناسب از آن استفاده میکند. یک توصیف ثبت میکند که ترمینال چند رنگ دارد، کدام بایتها مکاننما را به ردیف 12 ستون 40 میبرند، کلید F5 چه بایتهایی ارسال میکند و آیا قابلیت رسم خط زیرین (underline) با استایل خاص را دارد یا خیر. کتابخانه ncurses که تقریباً تمام رابطهای کاربری متنی (TUI) در Linux بر پایه آن ساخته شدهاند، این توصیف را هنگام شروع به کار میخواند. برنامههایی مانند top، less، nano و watch بدون آن نمیتوانند حتی یک صفحه را ترسیم کنند.
ورودی خود را بررسی کنید:
echo "$TERM"
tput longname
infocmp -1 | head -20tput longname توصیف قابلفهم برای انسان از هر چیزی که TERM نامگذاری میکند را چاپ میکند. برای xterm-256color این خروجی را چاپ میکند:
xterm with 256 colorsinfocmp -1 ورودی را دیکامپایل کرده و در هر خط یک قابلیت را چاپ میکند. این دستور قابلیتهای توسعهیافته (تعریفشده توسط کاربر) را نادیده میگیرد مگر اینکه -x را اضافه کنید، مانند infocmp -1 -x. اگر هر دو دستور کار کنند، پایگاهداده روی این ماشین، این ترمینال را میشناسد. این همان وضعیتی است که باید در سمت دیگر یک اتصال SSH نیز برقرار باشد.
چرا این مشکل فقط از طریق SSH رخ میدهد
SSH فقط نام را ارسال میکند و هیچ چیز دیگری همراه آن نیست. هنگامی که کلاینت درخواست یک pseudo terminal میکند، TERM همراه با آن درخواست ارسال میشود. راهنمای OpenSSH صراحتاً بیان میکند: "متغیر محیطی TERM همیشه هنگام درخواست pseudo-terminal ارسال میشود، زیرا پروتکل به آن نیاز دارد". بنابراین، shell ورود شما در VPS مقدار TERM=xterm-ghostty، یا xterm-kitty، یا هر نام دیگری که شبیهساز شما استفاده میکند را دریافت میکند. توصیفات مربوط به آن نام در لپتاپ شما و در پایگاه داده محلی آن باقی میماند. سروری که پیش از ساختهشدن شبیهساز شما ایجاد شده است، هرگز نام آن را نشنیده است. هیچ چیزی در خودِ اتصال SSH توصیفات ترمینال را کپی نمیکند و این یک تصمیم عمدی است: پروتکل فقط یک نام را حمل میکند، نه مجموعهای از قابلیتها را.
خطا را روی دستگاه خود با نامی که قطعاً وجود ندارد بازتولید کنید:
TERM=xterm-nosuchthing tput colors
echo "$?"tput: unknown terminal "xterm-nosuchthing"وضعیت خروج 3 است که ncurses آن را به عنوان نوع ترمینال ناشناخته یا پایگاه داده مفقود مستند کرده است. هر برنامه curses همان جستجو را انجام میدهد، بنابراین یک نام مفقود باعث ایجاد پیامهای متفاوتی از برنامههای مختلف میشود که همگی یک علت واحد دارند. nano با خطای Error opening terminal: xterm-nosuchthing. متوقف میشود که خطای استاندارد ncurses هنگام عدم توانایی در بارگذاری توصیفات در زمان شروع است. vim عبارت E558: Terminal entry not found in terminfo را چاپ میکند. less عبارت WARNING: terminal is not fully functional را چاپ میکند. یک pager که نیمهکاره کار میکند و یک ویرایشگر که از اجرا امتناع میورزد، ممکن است به عنوان باگهای بیارتباط به نظر برسند. آنها در واقع یک فایل مفقود مشابه هستند.
مکانهایی که ncurses برای جستجوی ورودی استفاده میکند
کتابخانه ncurses با ترتیبی ثابت جستجو میکند که در terminfo(5) مستند شده است:
$TERMINFO، در صورتی که تنظیم شده باشد. این اولین جایی است که بررسی میشود.$HOME/.terminfo.- تمام دایرکتوریهای فهرستشده در
$TERMINFO_DIRS. - مکانهای پیشفرض کامپایلشده که در Debian و Ubuntu شامل
/etc/terminfo،/lib/terminfoو/usr/share/terminfoهستند.
برای مشاهده فهرستی که نسخه ncurses سرور شما استفاده میکند، دستور infocmp -D را اجرا کنید؛ به جای تکیه بر مسیرهای بالا، این دستور دقیقترین اطلاعات را به شما میدهد. مرحله 2 کلید اصلی ماجراست. دایرکتوری home شما پیش از هر دایرکتوری سیستمی جستجو میشود، بنابراین قرار دادن یک فایل در ~/.terminfo مشکل lookup را برای حساب کاربری شما بدون نیاز به نصب پکیج یا دسترسی root حل میکند. تنها استثنا مرحله 1 است: اگر echo "$TERMINFO" در سرور خروجی داشته باشد، آن مکان ابتدا بررسی میشود و اگر ورودی همنامی در آنجا وجود داشته باشد، بر ورودی شما اولویت خواهد داشت.
راهکار 1: استفاده از ترمینالی که سرور آن را میشناسد
سریعترین راه برای رفع این مشکل، تعیین یک ترمینال متفاوت برای یک اتصال خاص است:
TERM=xterm-256color ssh user@203.0.113.10برای دائمی کردن این تنظیم برای آن میزبان خاص، در فایل ~/.ssh/config روی لپتاپ خود این مورد را اضافه کنید:
Host vps1
HostName 203.0.113.10
User deploy
SetEnv TERM=xterm-256colorاستفاده از SetEnv برای نادیده گرفتن TERM نیازمند نسخه OpenSSH 8.7 یا جدیدتر روی کلاینت است که در اوت 2021 منتشر شد. کلاینتهای قدیمیتر بدون توجه به این خط، مقدار TERM مربوط به شبیهساز ترمینال شما را ارسال میکنند. TERM تنها متغیری است که نیازی به اجازه سرور ندارد: در مستندات آمده است که «مشابه SendEnv، با این استثنا که برای متغیر TERM، سرور باید برای پذیرش متغیر محیطی آماده باشد». بنابراین این روش حتی در برابر یک sshd سختگیرانه که هیچ خط AcceptEnv ندارد نیز کار میکند.
هزینه این کار: از دست دادن تمام ویژگیهایی که شبیهساز شما فراتر از xterm-256color ساده توصیف میکند. این شامل رنگهای 24 بیتی که از طریق قابلیت RGB تبلیغ میشوند و زیرخطهای استایلدار از طریق Smulx است. برنامههایی که به ورودی terminfo متکی هستند، دیگر نمیتوانند این قابلیتها را ببینند، بنابراین به رنگهای 256 تایی و زیرخط ساده بازمیگردند، مگر اینکه آنها را طوری پیکربندی کنید که به هر حال آن دنبالهها (sequences) را ارسال کنند. برای مثال، Vim همچنان میتواند با set termguicolors رنگهای 24 بیتی را نمایش دهد، زیرا دنبالههای داخلی t_8f و t_8b آن برای اکثر ترمینالها کار میکنند. صفحه نمایش کار میکند، اما صرفاً قابلیتهای کمتری نسبت به ترمینالی که انتخاب کردهاید دارد.
این مشکل را با افزودن export TERM=xterm-256color به فایل .bashrc در سرور حل نکنید. آن فایل برای هر اتصال اجرا میشود، از جمله اتصالاتی که از ترمینالی با نام شناختهشده برای سرور برقرار شدهاند؛ بنابراین باعث افت کیفیت نشستهایی میشود که پیش از این مشکلی نداشتند. این تغییر را روی کلاینت نگه دارید، جایی که میدانید از چه شبیهساز ترمینالی استفاده میکنید.
راهکار 2: ورودی terminfo خود را یکبار به سرور ارسال کنید
این راهکار، شبیهساز ترمینال شما را دستنخورده باقی میگذارد. ورودی را بهصورت محلی Decompile کنید، آن را از طریق SSH منتقل کرده و در مقصد Compile کنید:
infocmp -x | ssh user@203.0.113.10 -- tic -x -infocmp -x ورودی مربوط به TERM فعلی شما را به عنوان متن منبع، شامل قابلیتهای توسعهیافته (تعریفشده توسط کاربر)، چاپ میکند. tic -x آن منبع را در سرور به یک توصیف باینری تبدیل میکند. استفاده از -x در هر دو سمت ضروری است؛ زیرا بدون آن، قابلیتهایی مانند Smulx در حین انتقال حذف میشوند و شما نسخهای تنزلیافته از ترمینال خود را ارسال خواهید کرد.
tic در صورت امکان در دایرکتوری سیستم مینویسد و اگر کاربر دسترسی نوشتن نداشته باشد، به $HOME/.terminfo بازمیگردد. یک حساب کاربری معمولی در VPS از دایرکتوری home استفاده میکند که همان چیزی است که شما نیاز دارید. همچنین میتوانید مقصد را نامگذاری کنید:
infocmp -x | ssh user@203.0.113.10 -- tic -x -o '~/.terminfo' /dev/stdinکوتیشنهای اطراف ~/.terminfo صرفاً تزئینی نیستند. ssh کلمات دستور را به یک رشته واحد تبدیل کرده و به shell راه دور تحویل میدهد؛ بنابراین اگر ~ بدون کوتیشن باشد، ابتدا توسط shell محلی شما بسط داده میشود. در نتیجه، شما یک /home/yourname/.terminfo تحتاللفظی به ماشینی میفرستید که ممکن است نام حساب کاربری شما در آن متفاوت باشد. tic با خطای مجوز مواجه میشود یا در مسیری مینویسد که ncurses هرگز آن را جستجو نمیکند. با کوتیشن گذاشتن دور tilde، اجازه دهید shell راه دور آن را بسط دهد.
وارد شوید و بررسی کنید:
ssh user@203.0.113.10
tput longname
ls -R ~/.terminfotput longname که توصیف ترمینال شما را چاپ میکند، به این معنی است که جستجو اکنون موفقیتآمیز بوده است و ls فایل کامپایلشده را در زیرشاخهای که با اولین حرف نام ترمینال نامگذاری شده، نشان میدهد. سپس top یا watch -n1 uptime که بازترسیم را از طریق همان کتابخانه انجام میدهد را اجرا کنید تا تأیید شود که یک برنامه curses واقعی، صفحه را بهدرستی ترسیم میکند.
هزینه این کار: یک مرحله برای هر سرور، و ورودی در دایرکتوری home یک حساب کاربری روی یک ماشین باقی میماند. اگر VPS را بازسازی کنید، این ورودی از بین میرود. این دستور را در ابزاری که برای provisioning و مدیریت همزمان چندین سرور استفاده میکنید قرار دهید تا هر میزبان جدید، از همان ابتدا با ورودی کامپایلشده آماده باشد.
رفع 3: نصب دیتابیس extended terminfo
اگر دسترسی root دارید و میخواهید نام ترمینال برای تمام حسابهای کاربری روی سیستم شناسایی شود:
sudo apt update
sudo apt install ncurses-term
tput -T xterm-ghostty longnameبسته ncurses-term شامل توصیفات ترمینالی است که در نصب پایه وجود ندارند. این کار مشکل نام ترمینال را برای root و سایر کاربران برطرف میکند، کاری که رفع 2 قادر به انجام آن نیست.
این روش تنها زمانی کارساز است که ورودی ترمینال شما در نسخه ncurses بستهبندیشده توسط توزیعتان موجود باشد، بنابراین به جای فرض کردن، آن را بررسی کنید. توزیع Ubuntu 24.04 شامل نسخه ncurses-bin 6.4+20240113-1ubuntu2.2 است (تا اکتبر 2026). ورودی Ghostty در نسخه ncurses 6.5-20241228 به بالادست (upstream) اضافه شده است که جدیدتر است، بنابراین apt install ncurses-term در Ubuntu 24.04 نمیتواند ورودی xterm-ghostty را تولید کند، فارغ از اینکه چند بار آن را اجرا کنید. دستور tput -T <name> longname برای بررسی است: اگر ورودی موجود باشد، توصیفات آن را چاپ میکند و در غیر این صورت با کد خروج 3، دستور unknown terminal را اجرا میکند.
برای نصب یک ورودی تکی به صورت سیستمی به جای نصب کل بسته، فایل منبع را کپی کرده و آن را با دسترسی root کامپایل کنید:
infocmp -x | ssh user@203.0.113.10 -- 'cat > /tmp/term.src'
ssh -t user@203.0.113.10 -- sudo tic -x -o /usr/share/terminfo /tmp/term.srcفلگ -t در دستور دوم، یک pseudo terminal اختصاص میدهد تا sudo بتواند درخواست رمز عبور کند. بدون این فلگ، sudo ممکن است با خطای sudo: no tty present and no askpass program specified متوقف شود.
اجازه دهید شبیهساز، انتقال را انجام دهد
برخی از شبیهسازها ابزار کمکی ارائه میدهند که اصلاح شماره 2 را برای شما انجام میدهد. kitty دارای یک ssh kitten است: kitten ssh myserver متصل شده و terminfo مربوط به kitty را بهطور خودکار به میزبان راه دور کپی میکند. مستندات آن همچنین روش دستی infocmp -a xterm-kitty | ssh myserver tic -x -o \~/.terminfo /dev/stdin را ارائه میدهد که در آن کاراکتر tilde به دلیلی که در بالا ذکر شد، escape شده است. Ghostty ابزار infocmp -x xterm-ghostty | ssh YOUR-SERVER -- tic -x - را مستند کرده است و از نسخه 1.2.0 به بعد، قابلیتهای یکپارچهسازی با shell را بهصورت opt-in (ssh-env و ssh-terminfo) ارائه میدهد که هر دو اصلاح را خودکار میکنند. مستندات آن همچنین یک wrapper به نام ghostty +ssh را توصیف میکند که تا اکتبر 2026، تنها در نسخههای توسعه (development builds) وجود دارد و در نسخههای 1.3.x عرضه نشده است.
این ابزارهای کمکی همان دستوراتی را اجرا میکنند که شما بهصورت دستی وارد کردید. دانستن روش دستی همچنان اهمیت دارد، زیرا این ابزارها نمیتوانند در شرایطی که اتصال از جای دیگری شروع میشود، روی یک jump host یا داخل یک اسکریپت عمل کنند.
هنگامی که خطا بازمیگردد
تحت sudo -i. یک shell ورود به سیستم با دسترسی root دارای HOME=/root است و sudo، TERM شما را حفظ میکند. اکنون ncurses مسیر /root/.terminfo را جستجو میکند که ورودی شما را در خود ندارد، بنابراین خطا فقط برای کاربر root بازمیگردد. با استفاده از sudo -i env تأیید کنید و خطوط HOME و TERM را بخوانید. ورودی را در دایرکتوری سیستم نصب کنید یا یک کپی از آن را در /root/.terminfo قرار دهید.
داخل tmux یا screen. این برنامهها TERM خاص خود را برای برنامههایی که درون آنها اجرا میشوند تنظیم میکنند که معمولاً screen-256color یا tmux-256color است. یک سرور قدیمی، screen-256color را میشناسد و ممکن است tmux-256color را نشناسد، بنابراین shell بیرونی سالم است در حالی که همه چیز در داخل session با خطا مواجه میشود. علت همان است، اما نام متفاوت است. دستور tput -T tmux-256color longname را روی سرور اجرا کنید تا ببینید کدامیک از این دو را دارد. یک میز کار ترمینال که حول tmux ساخته شده این موضوع را تا روزی که به میزبانی که هنوز اصلاح نکردهاید متصل شوید، پنهان نگه میدارد.
روی یک سرور تازه. ~/.terminfo برای هر حساب کاربری و هر ماشین منحصربهفرد است، بنابراین یک VPS بازسازیشده دوباره خالی شروع میشود.
صفحه نمایش ترسیم میشود، کلیدها بد عمل میکنند. اگر نمایشگر مشکلی ندارد اما کلیدهای Home، End یا کلیدهای تابعی (function keys) کاراکترهای اضافی درج میکنند، نام به ورودیای ترجمه شده است که با ترمینال شما مطابقت ندارد. توالی کلیدها از همان ورودی terminfo میآیند که قابلیتهای ترسیم از آن میآیند، بنابراین یک ورودی تقریبی، کلیدهای تقریبی میدهد. این نتیجه معمولِ اصلاح 1 روی شبیهسازی است که توالی کلیدهای آن با xterm متفاوت است. اصلاح 2 پاسخ این مشکل است، زیرا فقط ورودی واقعی شبیهساز شما، توالیهای صحیح را حمل میکند.
FAQ
چرا در SSH فقط خطای "unknown terminal type" را میبینم؟
زیرا پایگاه دادهای که باید ورودی ترمینال شما را در خود نگه دارد، همان پایگاه داده روی سرور است. شبیهساز ترمینال شما، توصیفات خود را روی ماشینی که روی آن اجرا میشود نصب میکند، بنابراین برنامههای محلی بدون هیچ تلاشی از سوی شما آن را پیدا میکنند. SSH فقط مقدار TERM را ارسال میکند، زیرا این پروتکل نام را همراه با درخواست pseudo-terminal حمل میکند. ncurses در سمت سرور، نام را در پایگاه داده راه دور جستجو میکند و چیزی نمییابد، بنابراین initscr با شکست مواجه شده و برنامه متوقف میشود.
آیا میتوانم این مشکل را بدون دسترسی root روی سرور حل کنم؟
بله. ncurses قبل از هر دایرکتوری سیستمی، $HOME/.terminfo را جستجو میکند و تنها متغیر $TERMINFO که روی سرور تنظیم شده باشد زودتر از آن بررسی میشود، بنابراین در حالت عادی، وجود یک ورودی در آن مسیر برای حساب کاربری شما کافی است. دستور infocmp -x | ssh user@host -- tic -x - را یکبار برای هر سرور اجرا کنید. tic زمانی که نتواند در مسیر سیستمی بنویسد (که حالت عادی برای یک حساب کاربری بدون امتیاز است)، در دایرکتوری home شما مینویسد. وارد سیستم شوید و tput longname را اجرا کنید تا تأیید شود که lookup اکنون به درستی انجام میشود.
با تنظیم TERM=xterm-256color برای یک میزبان، چه چیزی را از دست میدهم؟
تمام قابلیتهایی که شبیهساز شما فراتر از ورودی xterm-256color توصیف میکند؛ مانند رنگهای 24 بیتی از طریق RGB و زیرخطهای استایلدار از طریق Smulx. برنامههایی که به ورودی terminfo متکی هستند، نمیتوانند این قابلیتها را ببینند، بنابراین از نزدیکترین جایگزین (fallback) استفاده میکنند، مگر اینکه آنها را به شکل دیگری پیکربندی کنید؛ همانطور که گزینه termguicolors در Vim برای رنگها عمل میکند. دنبالههای کلیدهای تابعی (Function-key) نیز ممکن است با ترمینال واقعی شما متفاوت باشند. این تنظیم را به جای .bashrc روی سرور، در ~/.ssh/config روی کلاینت قرار دهید، زیرا در غیر این صورت، نشستهای ترمینالهایی که قبلاً به درستی کار میکردند نیز تنزل پیدا میکنند.
چرا پس از sudo -i خطا دوباره برمیگردد؟
sudo -i یک login shell را به عنوان root با HOME=/root شروع میکند، در حالی که مقدار TERM شما را حفظ میکند. سپس ncurses به جای دایرکتوری home شما، /root/.terminfo را جستجو میکند و چیزی نمییابد، بنابراین root همان خطایی را میبیند که حساب کاربری شما دیگر با آن مواجه نیست. دستور sudo -i env را اجرا کنید و خطوط HOME و TERM را بررسی کنید. ورودی را با sudo tic -x -o /usr/share/terminfo در دایرکتوری سیستمی کامپایل کنید یا آن را در /root/.terminfo کپی کنید.
آیا apt install ncurses-term همیشه مشکل را حل میکند؟
خیر. این دستور فقط ورودیهایی را اضافه میکند که در نسخه ncurses بستهبندیشده توسط توزیع شما وجود داشته است. Ubuntu 24.04 نسخه ncurses 6.4 (ncurses-bin 6.4+20240113-1ubuntu2.2، تا اکتبر 2026) را ارائه میدهد و ورودی Ghostty در نسخه upstream ncurses 6.5-20241228 اضافه شده است، بنابراین آن بسته نمیتواند شامل آن باشد. پیش از تکیه بر بسته، با tput -T <name> longname بررسی کنید و زمانی که بررسی همچنان ترمینال را ناشناخته گزارش میکند، خودتان ورودی را ارائه دهید.