FISH-FAQ(1) fish-shell FISH-FAQ(1)

fish-faq - پرسش‌های متداول درباره پوسته fish

این سند شامل پرسش‌ها و پاسخ‌های متداول (FAQ) درباره نحوه کارکرد، ویژگی‌ها، تفاوت‌های رفتاری با سایر پوسته‌ها و تنظیمات پوسته fish است.

صفحه راهنمای fish-for-bash-users(1) <> را مشاهده کنید.

از دستور set <> استفاده کنید:

set -x key value # typically set -gx key value
set -e key

از نسخه 3.1 فیش به بعد، می‌توانید مشابه سایر پوسته‌ها با استفاده از نحو key=value some command یک متغیر محیطی را صرفاً برای اجرای یک دستور تنظیم کنید. دو خط زیر رفتاری یکسان دارند - بر خلاف سایر پوسته‌ها، فیش در هر دو حالت مقدار value را چاپ می‌کند:

key=value echo $key
begin; set -lx key value; echo $key; end

توجه داشته باشید که "صادرشده (exported)" یک حوزه (scope) متغیر <#variables-scope> نیست، بلکه یک وضعیت اضافی برای آن است. یک متغیر می‌تواند سراسری و صادرشده، محلی و صادرشده، یا حتی جهان‌شمول و صادرشده باشد. معمولاً منطقی است که یک متغیر صادرشده را به صورت سراسری (global) تعریف کنید.

از set -q var استفاده کنید. برای نمونه، if set -q var; echo variable defined; end. برای بررسی چند متغیر می‌توانید از ترکیب با and و or به شکل زیر استفاده کنید:

if set -q var1; or set -q var2
    echo either variable defined
end

به یاد داشته باشید که یک متغیر تعریف‌شده ممکن است خالی نیز باشد؛ چه از طریق نداشتن هیچ عنصری (اگر با set var مقداردهی شده باشد) یا تنها با داشتن عناصر خالی (اگر با set var "" مقداردهی شده باشد). برای نحوه برخورد با این حالت‌ها ادامه مطلب را بخوانید.

از string length -q -- $var استفاده کنید. برای نمونه، if string length -q -- $var; echo not empty; end. توجه داشته باشید که string length فهرستی از چندین متغیر را به صورت فصل منطقی (یا / or) تفسیر می‌کند:

if string length -q -- $var1 $var2 $var3
    echo at least one of these variables is not empty
end

به عنوان روشی جایگزین، از test -n "$var" استفاده کنید، اما به یاد داشته باشید که متغیر باید داخل نقل‌قول دوتایی (دابل‌کوتیشن) قرار گیرد. برای نمونه، if test -n "$var"; echo not empty; end. دستور test عملگرهای «و» (-a) و «یا» (-o) مخصوص خود را ارائه می‌دهد:

if test -n "$var1" -o -n "$var2" -o -n "$var3"
    echo at least one of these variables is not empty
end

اگر می‌خواهید بدانید که آیا یک متغیر هیچ عنصری ندارد، از set -q var[1] استفاده کنید.

یک متغیر سراسری (global) با همین نام از قبل وجود دارد.

متغیرهای محیطی نظیر EDITOR یا TZ را می‌توان با استفاده از set -Ux به صورت جهان‌شمول (universal) تنظیم کرد. با این حال، اگر پیش از آغاز به کار فیش متغیر محیطی از قبل مقداردهی شده باشد (مثلاً توسط اسکریپت‌های ورود به سیستم یا مدیران سیستم)، آن متغیر به عنوان یک متغیر سراسری وارد فیش می‌شود. حوزه‌های متغیرها <#variables-scope> از «داخل به خارج» جستجو می‌شوند، بدین معنا که ابتدا متغیرهای محلی، سپس متغیرهای سراسری و در نهایت متغیرهای جهان‌شمول بررسی می‌گردند.

این بدان معناست که مقدار سراسری بر مقدار جهان‌شمول اولویت و تقدم دارد.

برای پیشگیری از این مشکل، می‌توانید تنظیمی را که فیش به ارث می‌برد تغییر دهید. اگر این کار امکان‌پذیر نیست، دستوری را به فایل پیکربندی خود <#configuration> (معمولاً ~/.config/fish/config.fish) بیفزایید:

set -gx EDITOR vim

فایل ~/.config/fish/config.fish [1] را ویرایش کنید؛ در صورتی که وجود ندارد آن را بسازید (به نقطه ابتدای نام فایل توجه داشته باشید).

بر خلاف bashrc. و profile.، این فایل همواره خوانده می‌شود؛ حتی در پوسته‌های غیرتعاملی یا هنگام ورود به سیستم.

برای اجرای یک دستور صرفاً در پوسته‌های تعاملی، دستور status is-interactive را به این شکل بررسی کنید:

if status is-interactive
    # use the coolbeans theme
    fish_config theme choose coolbeans
end
[1]
بخش "~/.config" در این مسیر می‌تواند از طریق متغیر $XDG_CONFIG_HOME تنظیم شود؛ این مسیر صرفاً مقدار پیش‌فرض است.

اعلان خط فرمان خروجی تابع fish_prompt است. آن را در مسیر ~/.config/fish/functions/fish_prompt.fish قرار دهید. برای نمونه، یک اعلان ساده به شکل زیر است:

function fish_prompt
    set_color $fish_color_cwd
    echo -n (prompt_pwd)
    set_color --reset
    echo -n ' > '
end

همچنین می‌توانید از ابزار پیکربندی تحت وب، fish_config <>، برای پیش‌نمایش و انتخاب از میان گالری اعلان‌های نمونه استفاده کنید.

یا اینکه می‌توانید از دستور fish_config در خط فرمان بهره ببرید:

> fish_config prompt show
# displays all the prompts fish ships with
> fish_config prompt choose disco
# loads the disco prompt in the current shell
> fish_config prompt save
# makes the change permanent

چنانچه مایل به ویرایش اعلان موجود خود هستید، می‌توانید از funced <> و funcsave <> استفاده کنید:

>_ funced fish_prompt
# This opens up your editor (set in $EDITOR).
# Modify the function,
# save the file and repeat to your liking.
# Once you are happy with it:
>_ funcsave fish_prompt

این موضوع در مورد fish_right_prompt <> و fish_mode_prompt <> نیز صدق می‌کند.

این مورد همان fish_mode_prompt <> است. هنگامی که با دستور fish_vi_key_bindings حالت vi را فعال کرده باشید، این نشانگر به صورت پیش‌فرض نمایش داده می‌شود.

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

اگر می‌خواهید این نمایش را تغییر دهید یا غیرفعال کنید، تابع fish_mode_prompt را مثلاً با استفاده از funced <> ویرایش کنید.

از ابزار پیکربندی تحت وب که توسط fish_config <> راه‌اندازی می‌شود استفاده کنید، یا مجموعه متغیرهای محیطی fish_color <#variables-color> را تغییر دهید، یا از زیردستور fish_config theme <> به این شکل بهره ببرید:

> fish_config theme show
# to demonstrate all the colorschemes
> fish_config theme choose coolbeans
# to load the "coolbeans" theme

مقدار متغیر fish_greeting را تغییر دهید یا یک تابع fish_greeting <> ایجاد کنید. برای نمونه، جهت حذف پیام خوش‌آمدگویی از دستور زیر استفاده کنید:

set -U fish_greeting

یا چنانچه ترجیح می‌دهید از متغیر جهان‌شمول استفاده نکنید، دستور زیر را به کار ببرید:

set -g fish_greeting

در فایل config.fish <#configuration>.

بخشی از دستور را تایپ کرده و سپس کلیدهای پیکان بالا (↑) یا پایین (↓) را بفشارید تا میان تطابق‌های تاریخچه پیمایش کنید، یا کلیدهای ctrl-r را بزنید تا تاریخچه در یک صفحه‌بندی‌کننده (pager) قابل جستجو باز شود. در این صفحه‌بندی‌کننده می‌توانید به ترتیب با زدن ctrl-r یا ctrl-s میان تاریخچه‌های قدیمی‌تر یا جدیدتر حرکت کنید.

کلیدهای میان‌بر پیش‌فرض دیگر شامل ctrl-p (بالا) و ctrl-n (پایین) هستند. برای اطلاعات بیشتر بخش تاریخچه دستورات قابل جستجو <#history-search> را مشاهده کنید.

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

به عنوان یک حالت ویژه، در بیشتر مواقع جایگزینی تاریخچه به صورت sudo !! به کار می‌رود. در این شرایط کلیدهای alt-s را بفشارید تا آخرین خط فرمان شما با پیشوند sudo فراخوانی شود (یا در صورت وجود هر متنی در خط فرمان فعلی، پیشوند sudo را روی آن فعال یا غیرفعال کند).

به طور کلی، بازیابی تاریخچه در فیش به این شکل عمل می‌کند:

  • مشابه سایر پوسته‌ها، کلید پیکان بالا (up) خطوط کامل را از آخرین خط اجراشده فراخوانی می‌کند؛ بنابراین به جای تایپ !!، کافی است کلید پیکان بالا را فشار دهید.
  • اگر خط موردنظر شما مربوط به گذشته‌های دورتر در تاریخچه است، بخشی از آن خط را تایپ کرده و سپس یک یا چند بار کلید پیکان بالا را بزنید. با این کار خطوط فراخوانی‌شده بر اساس این متن فیلتر می‌شوند و بسیار سریع‌تر به خط موردنظرتان می‌رسید. این سازوکار جایگزین دستوراتی چون "!vi"، "!?bar.c" و مانند آن است. در صورتی که تمایل دارید زمینه و بافت بیشتری را مشاهده کنید، می‌توانید ctrl-r را بزنید تا تاریخچه در صفحه‌بندی‌کننده باز شود.
  • کلید alt-up آرگومان‌ها را به صورت تکی از آخرین آرگومان در آخرین خط اجراشده فراخوانی می‌کند. این قابلیت می‌تواند به جای "!$" به کار رود.

برای جزئیات بیشتر درباره ویرایش خط در فیش، مستندات ویرایشگر <#editor> را ببینید.

با این وجود، می‌توانید با استفاده از کوتاه‌نوشت‌ها (Abbreviations) <#abbreviations> جایگزینی تاریخچه را پیاده‌سازی کنید. در اینجا فقط برای !! آورده شده است:

function last_history_item; echo $history[1]; end
abbr -a !! --position anywhere --function last_history_item

این دستور را اجرا کنید تا در هر کجای خط فرمان، !! با آخرین مدخل تاریخچه جایگزین شود. برای ماندگار شدن، آن را در config.fish <#configuration> قرار دهید.

پوسته fish برای زیردستورها از پرانتز استفاده می‌کند. برای نمونه:

for i in (ls)
    echo $i
end

همچنین فیش از نحو آشنای $() حتی درون نقل‌قول‌ها نیز پشتیبانی می‌کند. کاراکتر بک‌تیک (backtick) پشتیبانی نمی‌شود زیرا استفاده از آن حتی در پوسته‌های POSIX نیز منع شده است؛ این نویسه‌ها قابلیت تودرتویی ضعیفی دارند و تمایز آن‌ها از نقل‌قول تکی ('') دشوار است.

بر خلاف سایر پوسته‌ها، فیش خروجی جایگزینی دستورات را تنها بر اساس خطوط جدید (newline) تفکیک می‌کند، نه بر مبنای فاصله‌ها، تب‌ها یا نویسه‌های موجود در $IFS.

این بدان معناست که اگر دستور زیر را اجرا کنید:

count (printf '%s ' a b c)

مقدار 1 چاپ خواهد شد، زیرا عبارت "a b c " به صورت یکپارچه به کار گرفته شده است. اما اگر بنویسید:

count (printf '%s\n' a b c)

مقدار 3 چاپ می‌شود، چرا که آرگومان‌های "a"، "b" و "c" را به صورت جداگانه به دستور count داده است.

در بیشتر مواقع، تفکیک بر پایه فاصله‌ها ناخواسته است، بنابراین این رفتار یک بهبود به شمار می‌رود؛ در واقع به همین دلیل است که معمولاً درباره مشکلات نام فایل‌های حاوی فاصله می‌شنوید.

با این حال گاهی اوقات، به ویژه با ابزارهایی مانند pkg-config و برنامه‌های مرتبط، تفکیک بر پایه فاصله مورد نیاز است.

در این حالت‌ها از string split -n " " به شکل زیر استفاده کنید:

g++ example_01.cpp (pkg-config --cflags --libs gtk+-2.0 | string split -n " ")

گزینه -n باعث می‌شود عناصر خالی حذف شوند، مشابه رفتاری که پوسته‌های POSIX انجام می‌دهند.

از متغیر $status استفاده کنید. این متغیر جایگزین متغیر $? در سایر پوسته‌ها است.

somecommand
if test $status -eq 7
    echo "That's my lucky number!"
end

اگر فقط بررسی موفقیت یا عدم موفقیت دستور برایتان مهم است، می‌توانید دستور را مستقیماً به عنوان شرط دستور if اجرا کنید:

if somecommand
    echo "Command succeeded"
else
    echo "Command failed"
end

یا چنانچه می‌خواهید در صورت موفقیت یا شکست دستور اول، دستور دیگری اجرا شود، از and یا or استفاده کنید:

somecommand
or someothercommand

برای اطلاعات بیشتر، بخش شرایط <#syntax-conditional> و مستندات test <> و if <> را مشاهده کنید.

به طور خلاصه: نویسه عام (wildcard) را نقل‌قول <#quotes> یا گریزدهی (escape) <#escapes> کنید:

scp user@ip:/dir/"string-*"

هنگامی که فیش علامت ستاره * بدون نقل‌قول را می‌بیند، بسط نویسه عام <#expand-wildcard> را انجام می‌دهد. این بدان معناست که تلاش می‌کند نام فایل‌ها را با رشته داده‌شده تطبیق دهد.

اگر نویسه عام با هیچ فایلی تطابق نداشته باشد، فیش به جای اجرای دستور یک پیام خطا چاپ می‌کند:

> echo *this*does*not*exist
fish: No matches for wildcard '*this*does*not*exist'. See `help expand`.
echo *this*does*not*exist
     ^

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

این بدان معناست که دستوراتی مانند مثال فوق:

scp user@ip:/dir/string-*

یا

apt install postgres-*

به نظر می‌رسد که به درستی کار می‌کنند، زیرا بیشتر اوقات رشته تطابقی پیدا نمی‌کند و در نتیجه عبارت string-* ارسال می‌شود که توسط برنامه مقصد تفسیر می‌گردد.

اما این موضوع همچنین به این معنی است که هر لحظه با ایجاد یک فایل مطابق یا اجرای دستور در یک پوشه کاری متفاوت، ممکن است این دستورات از کار بیفتند؛ و برای مقابله با این مشکل bash به راهکارهای دورزدن نظیر این نیاز دارد:

for f in ./*.mpg; do
      # We need to test if the file really exists because
      # the wildcard might have failed to match.
      test -f "$f" || continue
      mympgviewer "$f"
done

(برگرفته از http://mywiki.wooledge.org/BashFAQ/004)

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

این رفتار مشابه گزینه "failglob" در پوسته bash است.

این مشکل ممکن است با پیام‌هایی نظیر "Received message too long"، "open terminal failed: not a terminal"، "Bad packet length"، یا "Connection refused" همراه با خروجی‌های عجیب در پیام‌های ssh_exchange_identification در گزارش اشکال‌زدایی نمایان شود.

این اتفاق معمولاً به این دلیل رخ می‌دهد که فیش فایل پیکربندی کاربر <#configuration> (~/.config/fish/config.fish) را همواره می‌خواند؛ چه پوسته تعاملی باشد، چه پوسته ورود، چه غیرتعاملی و چه غیرورود.

این رفتار کارها را ساده‌تر می‌کند، اما همچنین بدین معناست که اگر config.fish خروجی متنی تولید کند، این خروجی حتی در پوسته‌های غیرتعاملی نظیر پوسته‌ای که ابزارهای ssh/scp/rsync هنگام اتصال اجرا می‌کنند نیز تولید خواهد شد.

هر کدی در config.fish که خروجی تولید می‌کند باید با بررسی شرط status is-interactive (یا در صورت تمایل status is-login) محافظت شود:

if status is-interactive
  ...
end

همین موضوع برای نمونه هنگامی صادق است که tmux را بدون محافظ در config.fish اجرا کنید، که باعث ایجاد پیامی مانند sessions should be nested with care, unset $TMUX to force می‌گردد.

در یک ترمینال، برنامه در حال اجرا و خود ترمینال باید بر سر پهنای نویسه‌ها توافق داشته باشند تا حرکت مکان‌نما به درستی مدیریت شود.

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

گاهی اوقات بر سر پهنای نویسه‌ها ناهماهنگی پیش می‌آید. این موضوع علل و راه‌حل‌های متعددی دارد:

  • ممکن است نویسه موردنظر برای سیستم شما بیش از حد جدید باشد و سیستم آن را نشناسد - در این حالت باید از به‌کارگیری آن نویسه خودداری کنید.
  • ممکن است فیش یا ترمینال شما نویسه را نشناسند یا با آن اشتباه برخورد کنند - در این حالت باید فیش یا ترمینال اصلاح شود یا نسخه به‌روزرسانی‌شده آن را نصب کنید.
  • نویسه دارای پهنای «مبهم» (ambiguous) است و فیش پهنای آن را برابر X در نظر می‌گیرد در حالی که ترمینال آن را Y می‌داند. در این حالت یا باید پیکربندی ترمینال را تغییر دهید یا متغیر $fish_ambiguous_width را روی مقدار صحیح تنظیم کنید.
  • نویسه یک ایموجی (emoji) است و سیستم شما تنها از یونیکد ۸ پشتیبانی می‌کند. در این حالت متغیر $fish_emoji_width را برابر 1 قرار دهید.

این امر همچنین بدین معناست که چند مورد قابل پشتیبانی نیستند:

  • قلم‌های با پهنای نامساوی (غیر تک‌فاصله یا Non-monospace) - هیچ راهی برای فیش وجود ندارد تا پهنای یک نویسه خاص را تشخیص دهد، زیرا فیش تأثیری بر رندرینگ قلم ترمینال ندارد.
  • پهناهای متفاوت برای چندین نویسه با پهنای مبهم - هیچ راهی وجود ندارد که فیش بفهمد شما چه پهنایی را به هر یک از این نویسه‌ها اختصاص داده‌اید.

ممکن است ترمینال تمام پیش‌نیازهای فیش <> را برآورده نکند. لطفاً این مشکل را در سامانه پیگیری اشکالات ترمینال خود و فیش گزارش دهید.

چنانچه می‌خواهید فیش را حذف نصب کنید، ابتدا اطمینان حاصل نمایید که فیش به عنوان پوسته پیش‌فرض شما تنظیم نشده باشد. اگر مطمئن نیستید، دستور chsh -s /bin/bash را اجرا کنید.

اگر فیش را با یک مدیر بسته نصب کرده‌اید، از دستور حذف همان مدیر بسته استفاده کنید. اگر فیش را خودتان کامپایل و نصب کرده‌اید، با فرض اینکه آن را در مسیر usr/local/ نصب کرده باشید، دستورات زیر را اجرا کنید:

rm -Rf /usr/local/etc/fish /usr/local/share/fish ~/.config/fish
rm /usr/local/share/man/man1/fish*.1
cd /usr/local/bin
rm -f fish fish_indent

توسعه‌دهندگان پوسته fish

توسعه‌دهندگان پوسته fish

September 7, 2026 4.9