FISH-LANGUAGE(1) fish-shell FISH-LANGUAGE(1)

fish-language - مرور جامع زبان اسکریپت‌نویسی پوسته فیش

این سند یک مرور جامع از زبان اسکریپت‌نویسی fish است.

برای ویژگی‌های تعاملی، «استفاده تعاملی» (Interactive use) <> را ببینید.

پوسته‌هایی مانند fish با دادن دستورات به آن‌ها استفاده می‌شوند. یک دستور با نوشتن نام دستور و به دنبال آن هرگونه آرگومان اجرا می‌شود. به عنوان مثال:

echo hello world

دستور echo <> آرگومان‌های خود را بر روی صفحه نمایش می‌نویسد. در این مثال، خروجی hello world است.

همه چیز در fish با دستورات انجام می‌شود. دستوراتی برای تکرار سایر دستورات، دستوراتی برای مقداردهی متغیرها، دستوراتی برای برخورد با گروهی از دستورات به عنوان یک دستور واحد و غیره وجود دارند. تمام این دستورات از همان نحو پایه پیروی می‌کنند.

هر برنامه‌ای در رایانه شما می‌تواند به عنوان یک دستور در fish استفاده شود. اگر فایل برنامه در یکی از مسیرهای متغیر محیطی PATH قرار داشته باشد، می‌توانید فقط نام برنامه را برای استفاده از آن تایپ کنید. در غیر این صورت، نام کامل فایل، شامل مسیر دایرکتوری (مانند /home/me/code/checkers/checkers یا ../checkers) لازم است.

در اینجا فهرستی از برخی دستورات کاربردی آورده شده است:

  • دستور cd <>: تغییر دایرکتوری جاری
  • ls: فهرست کردن فایل‌ها و دایرکتوری‌ها
  • man: نمایش صفحه راهنما - دستور man ls را برای دریافت راهنما درباره دستور "ls" خود، یا man mv را برای کسب اطلاعات درباره "mv" امتحان کنید.
  • mv: جابه‌جا کردن (تغییر نام) فایل‌ها
  • cp: کپی کردن فایل‌ها
  • دستور open <>: باز کردن فایل‌ها با برنامه پیش‌فرضی که به هر نوع فایل مرتبط است
  • less: نمایش محتویات فایل‌ها

دستورات و آرگومان‌ها با نویسه فاصله ' ' از یکدیگر جدا می‌شوند. هر دستور یا با یک خط جدید (با فشردن کلید اینتر/return) یا با نقطه-ویرگول ; پایان می‌یابد. با جدا کردن دستورات با نقطه-ویرگول، می‌توان چندین دستور را در یک خط نوشت.

سوییچ (switch) یک نوع خاص و بسیار رایج از آرگومان است. سوییچ‌ها تقریباً همیشه با یک یا چند خط تیره - شروع می‌شوند و شیوه عملکرد یک دستور را تغییر می‌دهند. به عنوان مثال، دستور ls معمولاً نام تمام فایل‌ها و دایرکتوری‌های موجود در دایرکتوری کاری فعلی را فهرست می‌کند. با استفاده از سوییچ -l، رفتار ls تغییر می‌یابد تا نه تنها نام فایل، بلکه اندازه، مجوزها، مالک و زمان آخرین تغییر هر فایل را نیز نمایش دهد.

سوییچ‌ها در دستورات مختلف متفاوت هستند و معمولاً در صفحه راهنمای هر دستور مستند شده‌اند. با این حال، برخی از سوییچ‌ها برای اکثر دستورات مشترک هستند. به عنوان مثال، سوییچ --help معمولاً یک متن راهنما را نمایش می‌دهد، --version نسخه دستور را نمایش می‌دهد، و -i اغلب اعلان تعاملی را پیش از انجام عملیات فعال می‌کند. دستور man your-command-here را امتحان کنید تا اطلاعاتی درباره سوییچ‌های دستور خود به دست آورید.

بنابراین ایده اصلی fish مشابه سایر پوسته‌های یونیکس است: یک خط فرمان دریافت می‌کند، بسط‌ها (expansions) را اجرا می‌کند، و سپس نتیجه را به عنوان یک دستور اجرا می‌نماید.

در اینجا برخی از اصطلاحات استفاده‌شده در این صفحه و در سراسر سایر مستندات fish را تعریف می‌کنیم:

  • آرگومان (Argument): پارامتری که به یک دستور داده می‌شود. در echo foo، بخش "foo" یک آرگومان است.
  • دستور توکار (Builtin): دستوری که توسط خود پوسته پیاده‌سازی شده است. دستورات توکار چنان با عملکرد پوسته گره خورده‌اند که پیاده‌سازی آن‌ها به عنوان دستورات خارجی غیرممکن است. در echo foo، بخش "echo" یک دستور توکار است.
  • دستور (Command): برنامه‌ای که پوسته می‌تواند اجرا کند، یا به طور خاص‌تر، یک برنامه خارجی که پوسته آن را در فرآیندی دیگر اجرا می‌کند. دستورات خارجی به صورت فایل‌های اجرایی روی سیستم شما ارائه می‌شوند. در echo foo بخش "echo" یک دستور توکار است، و در command echo foo بخش "echo" یک دستور خارجی است که توسط فایلی مانند /bin/echo تأمین می‌شود.
  • تابع (Function): بلوکی از دستورات که می‌توان آن‌ها را به‌گونه‌ای فراخوانی کرد که گویی یک دستور واحد هستند. با استفاده از توابع، می‌توان چندین دستور ساده را به یک دستور پیشرفته‌تر متصل کرد.
  • کار (Job): یک پایپ‌لاین یا دستورِ در حال اجرا.
  • پایپ‌لاین (Pipeline): مجموعه‌ای از دستوراتِ متصل‌به‌هم به طوری که خروجی یک دستور، ورودی دستور بعدی باشد. عبارت echo foo | grep foo یک پایپ‌لاین است.
  • تغییرمسیر (Redirection): عملیاتی که یکی از جریان‌های ورودی یا خروجی مرتبط با یک کار را تغییر می‌دهد.
  • سوییچ (Switch) یا گزینه (Option): نوع خاصی از آرگومان که رفتار یک دستور را تغییر می‌دهد. یک سوییچ تقریباً همیشه با یک یا دو خط تیره شروع می‌شود. در echo -n foo بخش "-n" یک گزینه است.

گاهی می‌خواهید به یک دستور آرگومانی بدهید که حاوی نویسه‌های خاص برای fish است، مانند فاصله‌ها، $ یا *. برای انجام این کار، می‌توانید از نقل‌قول‌ها (quotes) استفاده کنید:

rm "my file.txt"

تا فایلی به نام my file.txt را حذف کند، به جای اینکه سعی کند دو فایل مجزا به نام‌های my و file.txt را حذف نماید.

پوسته fish دو نوع نقل‌قول را می‌شناسد: تکی (') و دوگانه (")، که هر دو کمی متفاوت عمل می‌کنند.

درون نقل‌قول‌های تکی، fish هیچ‌گونه بسطی (expansion) انجام نمی‌دهد. درون نقل‌قول‌های دوگانه، fish فقط بسط متغیر و جایگزینی دستور در قالب $(command) را انجام می‌دهد. هیچ نوع بسط دیگری (از جمله بسط آکولاد یا بسط پارامتر) انجام نمی‌شود، و توالی‌های گریز (به عنوان مثال، \n) نادیده گرفته می‌شوند. در داخل نقل‌قول‌ها، فاصله سفید برای جداسازی آرگومان‌ها استفاده نمی‌شود و این امکان را می‌دهد که آرگومان‌های نقل‌قول‌شده حاوی فاصله باشند.

تنها توالی‌های گریز معنی‌دار درون نقل‌قول‌های تکی، \' است که از نقل‌قول تکی گریز می‌زند و \\ که از نماد بک‌اسلش گریز ایجاد می‌کند. تنها گریزهای معنی‌دار در نقل‌قول‌های دوگانه عبارتند از \" که از نقل‌قول دوگانه گریز می‌زند، \$ که از نویسه دلار گریز می‌زند، \ به همراه یک خط جدید که بک‌اسلش و خط جدید را حذف می‌کند، و \\ که از نماد بک‌اسلش گریز ایجاد می‌کند.

نقل‌قول‌های تکی هیچ معنای خاصی در داخل نقل‌قول‌های دوگانه ندارند و برعکس.

مثال‌های بیشتر:

grep 'enabled)$' foo.txt

خطوطی را که در foo.txt به enabled) ختم می‌شوند جستجو می‌کند (نویسه $ برای grep خاص است: با انتهای خط مطابقت دارد).

apt install "postgres-*"

تمام بسته‌هایی را که نام آن‌ها با "postgres-" شروع می‌شود نصب می‌کند، به جای اینکه در دایرکتوری جاری به دنبال فایل‌هایی با نام "postgres-something" بگردد.

بعضی از نویسه‌ها را نمی‌توان مستقیماً در خط فرمان نوشت. برای این نویسه‌ها، توالی‌های به‌اصطلاح گریز (escape sequences) در نظر گرفته شده‌اند. این توالی‌ها عبارتند از:

  • \a نشان‌دهنده نویسه هشدار (alert / زنگ) است.
  • \e نشان‌دهنده نویسه گریز (escape) است.
  • \f نشان‌دهنده نویسه تعویض صفحه (form feed) است.
  • \n نشان‌دهنده نویسه سطر جدید (newline) است.
  • \r نشان‌دهنده نویسه بازگشت به ابتدای سطر (carriage return) است.
  • \t نشان‌دهنده نویسه تب (tab) است.
  • \v نشان‌دهنده نویسه تب عمودی (vertical tab) است.
  • \xHH یا \XHH، که در آن HH یک عدد در مبنای ۱۶ (هگزادسیمال) است، نشان‌دهنده یک بایت داده با مقدار مشخص‌شده می‌باشد. به عنوان مثال، \x9 نویسه تب است. اگر از یک کدگذاری چندبایتی استفاده می‌کنید، این مورد می‌تواند برای وارد کردن رشته‌های نامعتبر استفاده شود. به طور معمول fish با کدگذاری ASCII یا UTF-8 اجرا می‌شود، بنابراین هر مقداری تا \X7f یک نویسه ASCII است.
  • \ooo، که در آن ooo یک عدد در مبنای ۸ (اکتال) است، نشان‌دهنده نویسه ASCII با مقدار مشخص‌شده می‌باشد. به عنوان مثال، \011 نویسه تب است. بالاترین مقدار مجاز \177 است.
  • \uXXXX، که در آن XXXX یک عدد هگزادسیمال است، نشان‌دهنده نویسه ۱۶-بیتی یونیکد با مقدار مشخص‌شده است. به عنوان مثال، \u9 نویسه تب است.
  • \UXXXXXXXX، که در آن XXXXXXXX یک عدد هگزادسیمال است، نشان‌دهنده نویسه ۳۲-بیتی یونیکد با مقدار مشخص‌شده است. به عنوان مثال، \U9 نویسه تب است. بالاترین مقدار مجاز U10FFFF است.
  • \cX، که در آن X یک حرف از الفبا است، نشان‌دهنده توالی کنترلی ایجادشده با فشردن کلید کنترل و حرف مشخص‌شده است. به عنوان مثال، \ci نویسه تب است. کدهای کنترلی C0 را در ویکی‌پدیا ببینید: https://en.wikipedia.org/wiki/C0_and_C1_control_codes#C0_controls

بعضی از نویسه‌ها برای پوسته معنای خاصی دارند. به عنوان مثال، آپاستروف ' بسط را غیرفعال می‌کند (بخش نقل‌قول‌ها را ببینید). برای اینکه به پوسته بگویید با این نویسه‌ها به صورت تحت‌اللفظی (literal) رفتار کند، با یک بک‌اسلش از آن‌ها گریز بزنید. به عنوان مثال، دستور:

echo \'hello world\'

عبارت 'hello world' را خروجی می‌دهد (شامل آپاستروف‌ها)، در حالی که دستور:

echo 'hello world'

عبارت hello world را خروجی می‌دهد (بدون آپاستروف‌ها). در حالت اول، پوسته با آپاستروف‌ها به عنوان نویسه‌های واقعی و تحت‌اللفظی ' رفتار می‌کند، در حالی که در حالت دوم با آن‌ها به عنوان اصلاح‌کننده‌های خاص بسط رفتار می‌نماید.

نویسه‌های خاص و توالی‌های گریز آن‌ها عبارتند از:

  • \  (بک‌اسلش و فاصله) از نویسه فاصله گریز می‌زند. این کار مانع از آن می‌شود که پوسته آرگومان‌ها را در محل فاصلهٔ گریز‌خورده تقسیم کند.
  • \$ از نویسه دلار گریز می‌زند.
  • \\ از نویسه بک‌اسلش گریز می‌زند.
  • \* از نویسه ستاره گریز می‌زند.
  • \? از نویسه علامت سؤال گریز می‌زند (اگر پرچم ویژگی qmark-noglob فعال باشد، این کار لازم نیست).
  • \~ از نویسه تیلده گریز می‌زند.
  • \# از نویسه هشتگ/شارپ گریز می‌زند.
  • \( از نویسه پرانتز باز گریز می‌زند.
  • \) از نویسه پرانتز بسته گریز می‌زند.
  • \{ از نویسه آکولاد باز گریز می‌زند.
  • \} از نویسه آکولاد بسته گریز می‌زند.
  • \[ از نویسه قلاب/براکت باز گریز می‌زند.
  • \] از نویسه قلاب/براکت بسته گریز می‌زند.
  • \< از نویسه کوچکتری گریز می‌زند.
  • \> از نویسه بزرگتری گریز می‌زند.
  • \& از نویسه امپرسند گریز می‌زند.
  • \| از نویسه خط عمودی (پایپ) گریز می‌زند.
  • \; از نویسه نقطه-ویرگول گریز می‌زند.
  • \" از نویسه نقل‌قول دوگانه گریز می‌زند.
  • \' از نویسه آپاستروف (نقل‌قول تکی) گریز می‌زند.

به عنوان یک حالت خاص، اگر بلافاصله پس از \ یک خط جدید واقعی بیاید، این یک «ادامه‌دهنده» ("continuation") است و به fish می‌گوید که شکست خط را نادیده بگیرد و دریافت ورودی را از ابتدای خط بعدی از سر بگیرد (بدون ایجاد هیچ فاصله سفید یا پایان دادن به یک توکن).

اکثر برنامه‌ها از سه جریان ورودی/خروجی (I/O) استفاده می‌کنند:

  • ورودی استاندارد (stdin) برای خواندن. به طور پیش‌فرض از صفحه‌کلید خوانده می‌شود.
  • خروجی استاندارد (stdout) برای نوشتن خروجی. به طور پیش‌فرض روی صفحه نمایش نوشته می‌شود.
  • خطای استاندارد (stderr) برای نوشتن خطاها و هشدارها. به طور پیش‌فرض روی صفحه نمایش نوشته می‌شود.

هر جریان دارای عددی به نام توصیف‌گر فایل (File Descriptor یا FD) است: ۰ برای stdin، ۱ برای stdout و ۲ برای stderr.

مقصد یک جریان را می‌توان با استفاده از چیزی به نام تغییرمسیر (redirection) تغییر داد. به عنوان مثال، echo hello > output.txt خروجی استاندارد دستور echo را به یک فایل متنی تغییرمسیر می‌دهد.

  • برای خواندن ورودی استاندارد از یک فایل، از <SOURCE_FILE استفاده کنید.
  • برای خواندن ورودی استاندارد از یک فایل یا از /dev/null در صورتی که قابل خواندن نباشد، از <?SOURCE_FILE استفاده کنید.
  • برای نوشتن خروجی استاندارد در یک فایل، از >DESTINATION استفاده کنید.
  • برای نوشتن خطای استاندارد در یک فایل، از 2>DESTINATION استفاده کنید. [1]
  • برای الحاق (ضمیمه کردن) خروجی استاندارد به انتهای یک فایل، از >>DESTINATION_FILE استفاده کنید.
  • برای الحاق خطای استاندارد به انتهای یک فایل، از 2>>DESTINATION_FILE استفاده کنید.
  • برای بازنویسی نشدن ("clobber" نشدن) یک فایل موجود، از >?DESTINATION یا 2>?DESTINATION استفاده کنید. این تغییرمسیر به عنوان "noclobber" شناخته می‌شود.

مقدار DESTINATION می‌تواند یکی از موارد زیر باشد:

  • یک نام فایل برای نوشتن خروجی در آن. اغلب >/dev/null برای بی‌صدا کردن خروجی با نوشتن آن در فایل ویژه چاهک داده ("sinkhole").
  • یک امپرسند (&) به همراه شماره یک توصیف‌گر فایل دیگر مانند &2 برای خطای استاندارد. خروجی در توصیف‌گر مقصد نوشته خواهد شد.
  • یک امپرسند به همراه یک علامت منفی (&-). توصیف‌گر فایل بسته خواهد شد. توجه: این کار ممکن است باعث شکست برنامه شود زیرا عملیات نوشتن آن ناموفق خواهد بود.

جهت سهولت، می‌توان از تغییرمسیر &> برای هدایت همزمان stdout و stderr به یک مقصد واحد استفاده کرد. به عنوان مثال، echo hello &> all_output.txt هر دو خروجی stdout و stderr را به فایل all_output.txt هدایت می‌کند. این معادل با دستور echo hello > all_output.txt 2>&1 است. همچنین می‌توانید از &>> برای الحاق هر دو خروجی stdout و stderr به همان مقصد استفاده نمایید.

هر توصیف‌گر فایل دلخواه را می‌توان با افزودن شماره FD به عنوان پیشوند به تغییرمسیر، در عملیات تغییرمسیر استفاده کرد.

  • برای تغییرمسیر ورودی توصیف‌گر N، از N<DESTINATION استفاده کنید.
  • برای تغییرمسیر خروجی توصیف‌گر N، از N>DESTINATION استفاده کنید.
  • برای الحاق خروجی توصیف‌گر N به یک فایل، از N>>DESTINATION_FILE استفاده کنید.

توصیف‌گرهای فایل را نمی‌توان با تغییرمسیر ورودی <? استفاده کرد، بلکه فقط با تغییرمسیر ورودی عادی < قابل استفاده هستند.

به عنوان مثال:

# Write `foo`'s standard error (file descriptor 2)
# to a file called "output.stderr":
foo 2> output.stderr
# if $num doesn't contain a number,
# this test will be false and print an error,
# so by ignoring the error we can be sure that we're dealing
# with a number in the "if" block:
if test "$num" -gt 2 2>/dev/null
    # do things with $num as a number greater than 2
else
    # do things if $num is <= 2 or not a number
end
# Save `make`s output in a file:
make &>/log
# Redirections stack and can be used with blocks:
begin
    echo stdout
    echo stderr >&2 # <- this goes to stderr!
end >/dev/null # ignore stdout, so this prints "stderr"
# print all lines that include "foo" from myfile, or nothing if it doesn't exist.
string match '*foo*' <?myfile

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

[1]
نسخه‌های قبلی fish اجازه مشخص کردن این مورد را به صورت ^DESTINATION نیز می‌دادند، اما این کار باعث خاص شدن یک نویسه دیگر می‌شد، بنابراین منسوخ و حذف گردید. بخش پرچم‌های ویژگی (feature flags) را ببینید.

روش دیگری برای تغییرمسیر جریان‌ها، استفاده از یک پایپ (pipe / لوله) است. پایپ جریان‌ها را به یکدیگر متصل می‌کند. معمولاً خروجی استاندارد یک دستور به ورودی استاندارد دستور دیگر متصل می‌شود. این کار با جدا کردن دستورات با نویسه پایپ | انجام می‌گیرد. به عنوان مثال:

cat foo.txt | head

دستور cat foo.txt محتویات foo.txt را به stdout ارسال می‌کند. این خروجی به عنوان ورودی برای برنامه head فراهم می‌شود، که ۱۰ خط اول ورودی خود را چاپ می‌کند.

امکان ارسال یک توصیف‌گر فایل خروجی متفاوت به پایپ وجود دارد، که این کار با افزودن شماره FD آن و نماد تغییرمسیر خروجی به عنوان پیشوند به پایپ انجام می‌شود. به عنوان مثال:

make fish 2>| less

تلاش می‌کند تا fish را بیلد کند، و هرگونه خطایی با استفاده از پیجر (صفحه‌بند) less نمایش داده خواهد شد. [2]

جهت سهولت، پایپ &| (و همچنین نام مستعار |& که توسط Bash نیز پشتیبانی می‌شود) هر دو خروجی‌های stdout و stderr را به همان فرآیند هدایت می‌کنند.

[2]
منظور از یک پیجر ("pager") در اینجا برنامه‌ای است که خروجی را دریافت کرده و آن را صفحه‌بندی ("paginates") می‌کند. برنامه less فقط صفحه‌بندی انجام نمی‌دهد، بلکه امکان پیمایش دلخواه (حتی به عقب!) را نیز فراهم می‌سازد.

استفاده همزمان از چندین تغییرمسیر و یک پایپ امکان‌پذیر است. در این حالت، آن‌ها به این ترتیب خوانده می‌شوند:

1.
ابتدا پایپ تنظیم می‌شود.
2.
سپس تغییرمسیرها از چپ به راست ارزیابی می‌شوند.

این نکته زمانی اهمیت پیدا می‌کند که تغییرمسیرها با نحو &N به توصیف‌گرهای فایل دیگر ارجاع دهند. وقتی می‌نویسید >&2، این کار stdout را به جایی که stderr در همان لحظه به آن اشاره دارد هدایت می‌کند.

این تابع کمکی را در نظر بگیرید:

# Make a function that prints something to stdout and stderr
function print
    echo out
    echo err >&2
end

اکنون چند حالت را بررسی می‌کنیم:

# Redirect both stderr and stdout to less
print 2>&1 | less
# or
print &| less
# Show the "out" on stderr, silence the "err"
print >&2 2>/dev/null
# Silence both
print >/dev/null 2>&1

هنگامی که کاری را در fish آغاز می‌کنید، خود fish مکث خواهد کرد و کنترل ترمینال را به برنامه‌ای که به تازگی شروع کرده است می‌دهد. گاهی می‌خواهید به استفاده از خط فرمان ادامه دهید و کار در پس‌زمینه اجرا شود. برای ایجاد یک کار در پس‌زمینه، یک علامت امپرسند & را به انتهای دستور خود اضافه کنید. این کار به fish می‌گوید که آن کار را در پس‌زمینه اجرا کند. کارهای پس‌زمینه هنگام اجرای برنامه‌هایی که دارای رابط کاربری گرافیکی هستند بسیار مفیدند.

مثال:

emacs &

ویرایشگر متن emacs را در پس‌زمینه راه‌اندازی می‌کند. می‌توان در صورت نیاز از دستور fg <> برای آوردن مجدد آن به پیش‌زمینه استفاده کرد.

اکثر برنامه‌ها به شما این امکان را می‌دهند که با فشردن ctrl-z (که با نام ^Z نیز شناخته می‌شود)، اجرای برنامه را به حالت تعلیق درآورید و کنترل را به fish بازگردانید. پس از بازگشت به خط فرمان fish، می‌توانید برنامه‌های دیگر را شروع کرده و هر کاری که می‌خواهید انجام دهید. در صورت تمایل، می‌توانید با استفاده از دستور fg <> (پیش‌زمینه / foreground) به دستور معلق بازگردید.

اگر در عوض بخواهید یک کار معلق را به پس‌زمینه بفرستید، از دستور bg <> استفاده کنید.

برای دریافت فهرستی از تمام کارهای آغازشده فعلی، از دستور jobs <> استفاده کنید. این کارهای فهرست‌شده را می‌توان با دستور disown <> حذف کرد.

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

اگر پس از نویسه & یک نویسه غیرجداکننده بیاید، به عنوان عملگر پس‌زمینه تفسیر نمی‌شود. نویسه‌های جداکننده شامل فاصله سفید و نویسه‌های ;<>&| هستند.

توابع، برنامه‌هایی هستند که با نحو پوسته fish نوشته می‌شوند. آن‌ها دستورات مختلف و آرگومان‌هایشان را تحت یک نام واحد گروه‌بندی می‌کنند.

برای نمونه، در اینجا یک تابع ساده برای فهرست کردن دایرکتوری‌ها آورده شده است:

function ll
    ls -l $argv
end

خط نخست به فیش می‌گوید تابعی به نام ll تعریف کند تا بتوان با نوشتن ll در خط فرمان از آن استفاده کرد. خط دوم به فیش می‌گوید هنگامی که ll فراخوانی می‌شود، دستور ls -l $argv باید اجرا گردد. متغیر $argv یک متغیر از نوع فهرست است که همواره شامل تمامی آرگومان‌های ارسالی به تابع می‌باشد. در مثال بالا، این آرگومان‌ها به دستور ls منتقل می‌شوند. کلمه end در خط سوم، تعریف تابع را پایان می‌دهد.

فراخوانی این تابع به صورت ll /tmp/ در نهایت منجر به اجرای دستور ls -l /tmp/ خواهد شد که محتویات دایرکتوری /tmp را فهرست می‌کند.

این نوع از توابع با عنوان نام مستعار (alias) شناخته می‌شوند.

اعلان اعلان خط فرمان فیش (prompt) نیز در تابعی به نام fish_prompt <> تعریف شده است. این تابع زمانی که قرار است اعلان خط فرمان نمایش داده شود اجرا می‌گردد و خروجی آن، ظاهر اعلان را می‌سازد:

function fish_prompt
    # A simple prompt. Displays the current directory
    # (which fish stores in the $PWD variable)
    # and then a user symbol - a '►' for a normal user and a '#' for root.
    set -l user_char '►'
    if fish_is_root_user
        set user_char '#'
    end
    echo (set_color yellow)$PWD (set_color purple)$user_char
end

برای ویرایش یک تابع می‌توانید از دستور funced <> و برای ذخیره آن از funcsave <> استفاده کنید. این کار تابع را در یک فایل تابعی ذخیره می‌کند تا فیش در صورت نیاز آن را به طور خودکار بارگذاری کند.

دستور توکار functions <> می‌تواند تعریف فعلی یک تابع را نمایش دهد (دستور type <> نیز در صورت دریافت نام تابع، تعریف آن را نشان می‌دهد).

برای اطلاعات بیشتر درباره توابع، به مستندات دستور توکار function <> مراجعه کنید.

یکی از رایج‌ترین کاربردهای توابع، تغییر اندک در رفتار یک دستور از پیش موجود است. برای نمونه، ممکن است بخواهید دستور ls را به گونه‌ای بازتعریف کنید که خروجی را رنگی نمایش دهد. سوییچ فعال‌سازی رنگ‌ها در سیستم‌های گنو --color=auto است. یک نام مستعار در پوشش دستور ls ممکن است به این شکل باشد:

function ls
    command ls --color=auto $argv
end

چند نکته مهم وجود دارد که باید در مورد نام‌های مستعار مد نظر قرار گیرند:

  • همواره دقت کنید که متغیر $argv را به فهرست پارامترهای دستور پوشش‌داده‌شده اضافه کنید. این کار اطمینان حاصل می‌کند که اگر کاربر پارامترهای اضافی به تابع بدهد، آن پارامترها به دستور زیرین منتقل شوند.
  • اگر نام مستعار با دستور پوشش‌داده‌شده هم‌نام باشد، باید قبل از فراخوانی برنامه، عبارت command را قرار دهید تا به فیش اعلام شود که تابع نباید خودش را صدا بزند، بلکه باید دستور اصلی با همان نام را اجرا کند. اگر این کار را فراموش کنید، تابع تا ابد خود را فراخوانی خواهد کرد (حلقه بی‌نهایت). معمولاً فیش آن‌قدر هوشمند است که این موضوع را تشخیص دهد و از تکرار آن خودداری کند.

برای ساخت آسان تابعی با این ساختار، می‌توانید از دستور alias <> استفاده کنید. برخلاف سایر پوسته‌ها، این دستور صرفاً تابع می‌سازد - فیش مفهوم مستقلی به نام «alias» ندارد؛ ما صرفاً این واژه را برای چنین توابع پوششی ساده‌ای به کار می‌بریم. دستور alias <> بلافاصله یک تابع ایجاد می‌کند. استفاده از alias --save یا funcsave <> را در نظر داشته باشید تا تابع ایجادشده را در یک فایل بارگذاری خودکار ذخیره کنید، به جای اینکه هر بار نام مستعار را بازسازی نمایید.

به عنوان یک راهکار جایگزین، اختصارات abbreviations <#abbreviations> را امتحان کنید. این‌ها واژه‌هایی هستند که هنگام تایپ کردن بسط می‌یابند، نه اینکه توابع واقعی درون پوسته باشند.

توابع را می‌توان در خط فرمان یا در یک فایل پیکربندی تعریف کرد، اما امکان بارگذاری خودکار آن‌ها نیز وجود دارد. این کار مزایایی به همراه دارد:

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

هنگامی که فیش نیاز به بارگذاری یک تابع دارد، دایرکتوری‌های موجود در متغیر فهرستی $fish_function_path را برای یافتن فایلی با نام متشکل از نام تابع به علاوه پسوند .fish جستجو کرده و نخستین فایلی را که می‌یابد بارگذاری می‌کند.

برای نمونه اگر تلاش کنید چیزی به نام banana را اجرا کنید، فیش تمامی دایرکتوری‌های موجود در $fish_function_path را برای یافتن فایلی به نام banana.fish پیمایش کرده و اولین مورد را بارگذاری می‌کند.

به طور پیش‌فرض $fish_function_path شامل موارد زیر است:

  • دایرکتوری برای نگهداری توابع اختصاصی کاربران، معمولاً ~/.config/fish/functions (کنترل‌شده توسط متغیر محیطی XDG_CONFIG_HOME).
  • دایرکتوری برای توابع عمومی تمام کاربران سیستم، معمولاً /etc/fish/functions (در اصل $__fish_sysconfdir/functions).
  • دایرکتوری‌ها برای قرار دادن توابع اختصاصی نرم‌افزارهای دیگر. این دایرکتوری‌ها در زیرمجموعه $__fish_user_data_dir (معمولاً ~/.local/share/fish، کنترل‌شده توسط متغیر محیطی XDG_DATA_HOME) و در متغیر محیطی XDG_DATA_DIRS درون زیردایرکتوری به نام fish/vendor_functions.d قرار دارند. مقدار پیش‌فرض برای XDG_DATA_DIRS معمولاً /usr/share/fish/vendor_functions.d و /usr/local/share/fish/vendor_functions.d است.

اگر مطمئن نیستید، توابع شما احتمالاً متعلق به دایرکتوری ~/.config/fish/functions هستند.

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

بارگذاری خودکار برای گرداننده‌های رویداد (event handlers) نیز کار نخواهد کرد، زیرا فیش نمی‌تواند بداند که یک تابع قرار است هنگام وقوع یک رویداد اجرا شود، در حالی که هنوز آن تابع را بارگذاری نکرده است. برای اطلاعات بیشتر بخش گرداننده‌های رویداد را ببینید.

اگر فایلی با نام مناسب، تابع مورد نظر را تعریف نکند، فیش سایر فایل‌های بارگذاری خودکار را نخواهد خواند؛ بلکه به سراغ بررسی دستورات توکار و در نهایت دستورات خارجی می‌رود. این قابلیت امکان پوشش دادن (mask) تابعی را فراهم می‌کند که در ادامه مسیر $fish_function_path تعریف شده است؛ مثلاً زمانی که مدیر سیستم فایلی در /etc/fish/functions قرار داده که می‌خواهید آن را نادیده بگیرید.

اگر در حال توسعه برنامه‌ای دیگر هستید و می‌خواهید توابع فیش را برای آن نصب کنید، آن‌ها را در دایرکتوری توابع «تأمین‌کننده» (vendor) نصب نمایید. از آنجا که این مسیر در سیستم‌های مختلف متغیر است، می‌توانید با استفاده از pkgconfig و از طریق خروجی دستور pkg-config --variable functionsdir fish آن را پیدا کنید. سیستم نصب برنامه شما باید از مسیری سفارشی برای بازنویسی مسیر pkgconfig پشتیبانی کند تا توزیع‌کنندگان دیگر بتوانند به راحتی آن را تغییر دهند.

هر چیزی که بعد از نویسه # تا انتهای خط قرار گیرد، کامنت محسوب می‌شود. این یعنی صرفاً برای بهره‌مندی خواننده متن است و فیش آن را نادیده می‌گیرد.

این قابلیت برای توضیح اینکه چه کاری و چرا انجام می‌دهید کاربردی است:

function ls
    # The function is called ls,
    # so we have to explicitly call `command ls` to avoid calling ourselves.
    command ls --color=auto $argv
end

کامنت چندخطی در فیش وجود ندارد. اگر می‌خواهید کامنت را در چند خط امتداد دهید، ابتدای هر خط یک # بگذارید.

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

set -gx EDITOR emacs # I don't like vim.

پوسته فیش دارای دستورات توکاری است که امکان می‌دهند دستورات را تنها در صورت برآورده شدن معیاری خاص اجرا کنید: if <>، switch <>، and <> و or <>، و همچنین نحو آشنای &&/||.

دستور if <> در صورتی که شرط برقرار (true) باشد، یک بلوک از دستورات را اجرا می‌کند.

مشابه دیگر پوسته‌ها، اما برخلاف زبان‌های برنامه‌نویسی معمولی که ممکن است بشناسید، شرط در اینجا یک دستور است. فیش آن دستور را اجرا می‌کند و چنانچه وضعیت خروج آن درست (یعنی 0) باشد، بلوک if اجرا خواهد شد. برای مثال:

if test -e /etc/os-release
    cat /etc/os-release
end

این مثال از دستور test <> استفاده می‌کند تا بررسی کند آیا فایل /etc/os-release وجود دارد یا خیر. اگر وجود داشته باشد، دستور cat را اجرا می‌کند که محتوای آن را روی صفحه چاپ می‌نماید.

برخلاف پوسته‌های دیگر، دستور شرط بعد از نخستین کار (job) پایان می‌یابد و نیازی به واژه then نیست. ترکیب‌کننده‌هایی مانند and و or شرط را بسط می‌دهند.

نمونه‌ای پیچیده‌تر به همراه جایگزینی دستور:

if test "$(uname)" = Linux
    echo I like penguins
end

از آنجا که دستور test می‌تواند برای آزمایش‌های گوناگونی به کار رود، قرار دادن متغیرها و جایگزینی‌های دستور درون نقل‌قول اهمیت بالایی دارد. اگر $(uname) درون نقل‌قول قرار نمی‌گرفت و دستور uname هیچ متنی چاپ نمی‌کرد، عبارت test = Linux اجرا می‌شد که یک خطاست.

دستور if همچنین می‌تواند بندهای else if همراه با شرط‌های تکمیلی و یک بند else <> بپذیرد که در صورت نادرست بودن تمام شرط‌های قبلی اجرا می‌شود:

if test "$number" -gt 10
   echo Your number was greater than 10
else if test "$number" -gt 5
   echo Your number was greater than 5
else if test "$number" -gt 1
   echo Your number was greater than 1
else
   echo Your number was smaller or equal to 1
end

کلیدواژه not <> می‌تواند برای معکوس کردن وضعیت خروج به کار رود:

# Check if the file contains the string "fish" anywhere.
# This executes the `grep` command, which searches for a string,
# and if it finds it returns a status of 0.
# The `not` then turns 0 into 1 or anything else into 0.
# The `-q` switch stops it from printing any matches.
if not grep -q fish myanimals
    echo "You don't have fish!"
else
    echo "You have fish!"
end

سایر مواردی که معمولاً در شرط‌های if استفاده می‌شوند:

  • contains <> - برای بررسی اینکه آیا یک فهرست شامل عنصری خاص هست یا خیر (if contains -- /usr/bin $PATH)
  • string <> - برای نمونه جهت تطبیق رشته‌ها (if string match -q -- '*-' $arg)
  • path <> - برای بررسی اینکه آیا مسیرهایی با معیارهای معین وجود دارند یا خیر (if path is -rf -- ~/.config/fish/config.fish)
  • type <> - برای بررسی وجود یک دستور، تابع یا دستور توکار (if type -q git)

دستور switch <> برای اجرای یکی از چند بلوک دستور بر اساس مقدار یک رشته به کار می‌رود. این دستور می‌تواند چندین بلوک case <> را بپذیرد که هنگام تطبیق رشته اجرا می‌شوند. این بلوک‌ها می‌توانند از الگوهای عام (wildcards) بهره ببرند. برای نمونه:

switch (uname)
case Linux
    echo Hi Tux!
case Darwin
    echo Hi Hexley!
case DragonFly '*BSD'
    echo Hi Beastie! # this also works for FreeBSD and NetBSD
case '*'
    echo Hi, stranger!
end

برخلاف برخی پوسته‌ها یا زبان‌های برنامه‌نویسی دیگر، پدیده سقوط (fallthrough) وجود ندارد - اولین بلوک case منطبق اجرا شده و سپس جریان کنترل از ساختار switch خارج می‌شود.

برای بررسی‌های ساده می‌توانید از ترکیب‌کننده‌ها استفاده کنید. دستور and <> یا && در صورت موفقیت دستور اول، دستور دوم را اجرا می‌کند؛ در حالی که or <> یا || در صورت شکست دستور اول، دومی را اجرا می‌نمایند. برای نمونه:

# $XDG_CONFIG_HOME is a standard place to store configuration.
# If it's not set applications should use ~/.config.
set -q XDG_CONFIG_HOME; and set -l configdir $XDG_CONFIG_HOME
or set -l configdir ~/.config

توجه داشته باشید که ترکیب‌کننده‌ها به صورت تنبلی (lazy evaluation) اجرا می‌شوند - یعنی تنها بخشی که برای تعیین وضعیت نهایی لازم است اجرا می‌گردد.

مقایسه کنید:

if sleep 2; and false
    echo 'How did I get here? This should be impossible'
end

و:

if false; and sleep 2
    echo 'How did I get here? This should be impossible'
end

این دو دستور اساساً یک کار را انجام می‌دهند، اما حالت نخست ۲ ثانیه بیشتر طول می‌کشد زیرا دستور sleep همواره باید اجرا شود.

همچنین ممکن است حالتی داشته باشید که در آن توقف زودهنگام ضروری باشد:

if command -sq foo; and foo

اگر پردازش پس از پی بردن به اینکه دستور «foo» وجود ندارد ادامه می‌یافت، تلاش می‌کرد foo را اجرا کند و با خطای یافت نشدن دستور مواجه می‌شد!

ترکیب‌کننده‌ها گام به گام اجرا می‌شوند، بنابراین ساخت زنجیره‌های طولانی از آن‌ها پیشنهاد نمی‌شود چون ممکن است رفتاری ناخواسته ایجاد کنند. این مثال را در نظر بگیرید:

test -e /etc/my.config
or echo "OH NO WE NEED A CONFIG FILE"
and return 1

این زنجیره حتی اگر test هم موفق باشد، دستور return 1 را اجرا خواهد کرد! علت آن است که فیش دستور test -e /etc/my.config را اجرا کرده، متغیر $status را روی 0 می‌گذارد، سپس از echo عبور می‌کند و $status همچنان 0 باقی می‌ماند، و در نهایت return 1 را اجرا می‌کند چون $status هنوز 0 است.

بنابراین اگر شرط‌های پیچیده‌تری دارید یا می‌خواهید چند کار را پس از شکست یک دستور انجام دهید، استفاده از دستور if را مد نظر داشته باشید. در اینجا آن ساختار به این شکل خواهد بود:

if not test -e /etc/my.config
    echo "OH NO WE NEED A CONFIG FILE"
    return 1
end

مانند بیشتر زبان‌های برنامه‌نویسی، فیش نیز از حلقه‌های آشنای while <> و for <> برخوردار است.

حلقه while مانند یک if تکرارشونده عمل می‌کند:

while true
    echo Still running
    sleep 1
end

این حلقه هر ثانیه عبارت «Still running» را چاپ می‌کند. می‌توانید با کلیدهای ترکیبی ctrl-c آن را متوقف سازید.

حلقه‌های for مانند دیگر پوسته‌ها عمل می‌کنند که بیشتر شبیه حلقه for در پایتون است تا زبان‌هایی مثل C:

for file in *
    echo file: $file
end

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

set moreanimals bird fox
for animal in {cat,}fish dog $moreanimals
   echo I like the $animal
end

اگر به فهرستی از اعداد نیاز دارید، می‌توانید از دستور seq برای ساخت آن استفاده کنید:

for i in (seq 1 5)
    echo $i
end

دستور توکار break <> برای خروج از حلقه و continue <> برای رفتن به تکرار بعدی در دسترس هستند.

تغییرمسیرهای ورودی و خروجی (از جمله لوله‌ها و پایپ‌ها) را می‌توان روی حلقه‌ها نیز اعمال کرد:

while read -l line
    echo line: $line
end < file

علاوه بر این، یک بلوک begin <> وجود دارد که صرفاً دستورات را با یکدیگر گروه‌بندی می‌کند تا بتوانید خروجی را به یک بلوک هدایت کرده یا بدون نیاز به تکرار، از یک دامنه متغیر جدید استفاده نمایید:

begin
   set -l foo bar # this variable will only be available in this block!
end

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

  • کاراکترهای عام (Wildcards)، برای ایجاد نام فایل‌ها از روی الگوها - مانند *.jpg
  • بسط متغیر، برای استفاده از مقدار یک متغیر - مانند $HOME
  • جایگزینی دستور، برای بهره‌گیری از خروجی یک دستور دیگر - مانند $(cat /path/to/file)
  • بسط آکولاد، برای نوشتن کوتاه‌تر فهرست‌هایی با پیشوندها یا پسوندهای مشترک - مانند {/usr,}/bin
  • بسط مدک (تیلد)، برای تبدیل علامت ~ در ابتدای مسیرها به مسیر دایرکتوری خانگی - مانند ~/bin

بسط پارامترها به ۵۲۴۲۸۸ مورد محدود شده است. سیستم‌عامل برای تعداد آرگومان‌های هر دستور محدودیتی دارد و ۵۲۴۲۸۸ بسیار بالاتر از آن سقف است. این تدبیر برای جلوگیری از قفل شدن پوسته در اثر محاسبات بیهوده در نظر گرفته شده است.

هنگامی که یک پارامتر حاوی ستاره فاقد نقل‌قول * یا علامت سؤال ? باشد، فیش از آن به عنوان یک نویسه عام (wildcard) برای تطبیق فایل‌ها استفاده می‌کند.

  • نویسه * با هر تعداد کاراکتر (از جمله صفر کاراکتر) در یک نام فایل، به جز /، تطبیق می‌یابد.
  • نویسه ** با هر تعداد کاراکتر (از جمله صفر) تطبیق یافته و همچنین به زیردایرکتوری‌ها وارد می‌شود. اگر ** به تنهایی یک بخش مسیر باشد، برای سازگاری با سایر پوسته‌ها ممکن است با صفر بار تطبیق داده شود.
  • علامت ? می‌تواند با هر کاراکتر منفردی به جز / مطابقت یابد. این رفتار منسوخ شده و می‌توان از طریق فلگ ویژگی qmark-noglob آن را غیرفعال کرد تا ? یک نویسه معمولی در نظر گرفته شود.

تطبیق‌های نویسه‌های عام بدون حساسیت به بزرگی و کوچکی حروف مرتب می‌شوند. در هنگام مرتب‌سازی مواردی که حاوی عدد هستند، مرتب‌سازی به صورت طبیعی صورت می‌گیرد؛ به گونه‌ای که رشته‌های «1»، «5» و «12» مانند اعداد ۱، ۵ و ۱۲ مرتب می‌شوند.

فایل‌های مخفی (آن‌هایی که نامشان با یک نقطه آغاز می‌شود) در تطبیق عام در نظر گرفته نمی‌شوند مگر آنکه رشته الگوی عام، در آن موقعیت دارای نقطه باشد.

نویسه‌های عام هرگز به . (دایرکتوری جاری) یا .. (دایرکتوری والد) بسط نمی‌یابند.

مثال‌ها:

  • الگوی a* با تمامی فایل‌هایی که با «a» در دایرکتوری جاری آغاز می‌شوند تطبیق می‌یابد.
  • الگوی ** با تمام فایل‌ها و دایرکتوری‌های درون دایرکتوری جاری و تمامی زیردایرکتوری‌های آن مطابقت دارد.
  • الگوی ~/.* با تمامی فایل‌های مخفی (dotfiles) و دایرکتوری‌های موجود در دایرکتوری خانگی شما تطبیق پیدا می‌کند.

در اکثر دستورات، چنانچه بسط یک الگوی عام شکست بخورد، دستور اجرا نمی‌شود، متغیر $status روی مقداری غیر از صفر تنظیم شده و یک هشدار چاپ می‌گردد. این رفتار شبیه قابلیتی است که در bash با دستور shopt -s failglob فراهم می‌شود. استثنائاتی وجود دارد، از جمله دستورات set <> و path <>، بازنویسی متغیرها در overrides، دستور count <> و حلقه for <>. الگوهای عام این دستورات در صورت عدم تطبیق به صفر آرگومان بسط می‌یابند (بنابراین دستور اصلاً آن‌ها را نمی‌بیند)، شبیه رفتار shopt -s nullglob در بش.

مثال‌ها:

# List the .foo files, or warns if there aren't any.
ls *.foo
# List the .foo files, if any.
set foos *.foo
if count $foos >/dev/null
    ls $foos
end

برخلاف رفتار پیش‌فرض bash، فیش در صورت عدم یافتن تطبیق، کاراکتر عام را به همان شکل لفظی عبور نمی‌دهد؛ بنابراین برای دستوری مانند apt install که خود وظیفه تطبیق الگو را بر عهده دارد، باید از نقل‌قول استفاده کنید:

apt install "ncurses-*"

یکی از مهم‌ترین بسط‌ها در فیش، «بسط متغیر» است. این عمل شامل جایگزینی علامت دلار ($) به دنبال نام متغیر، با مقدار آن متغیر می‌باشد.

یک مثال ساده:

echo $HOME

این دستور $HOME را با دایرکتوری خانگی کاربر جاری جایگزین کرده و آن را به دستور echo <> ارسال می‌کند تا چاپ شود.

برخی متغیرها مانند $HOME از پیش مقداردهی شده‌اند زیرا فیش آن‌ها را به صورت پیش‌فرض تنظیم می‌کند یا فرآیند والد هنگام راه‌اندازی فیش، آن‌ها را منتقل کرده است. شما می‌توانید متغیرهای اختصاصی خود را با دستور set <> مقداردهی کنید:

set my_directory /home/cooluser/mystuff
ls $my_directory
# shows the contents of /home/cooluser/mystuff

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

گاهی یک متغیر مقداری ندارد چون تعریف نشده یا خالی است؛ در این صورت به هیچ چیز بسط نمی‌یابد:

echo $nonexistentvariable
# Prints no output.

برای جداسازی نام یک متغیر از متن، می‌توانید متغیر را درون نقل‌قول دوتایی یا آکولاد محصور کنید:

set WORD cat
echo The plural of $WORD is "$WORD"s
# Prints "The plural of cat is cats" because $WORD is set to "cat".
echo The plural of $WORD is {$WORD}s
# ditto

بدون نقل‌قول یا آکولاد، فیش تلاش می‌کند متغیری به نام $WORDs را بسط دهد که ممکن است وجود نداشته باشد.

نحو دوم یعنی {$WORD} حالت خاصی از بسط آکولاد است.

اگر متغیر $WORD در اینجا تعریف نشده باشد یا یک فهرست خالی باشد، حرف «s» چاپ نمی‌شود. با این حال اگر $WORD رشته خالی باشد (مانند پس از اجرای set WORD "")، حرف «s» چاپ خواهد شد.

برای کسب اطلاعات بیشتر درباره متغیرهای پوسته، بخش متغیرهای پوسته را مطالعه فرمایید.

بسط متغیرها در رشته‌های داخل نقل‌قول دوتایی نیز صورت می‌گیرد. درون نقل‌قول دوتایی ("این‌ها")، متغیرها همواره دقیقاً به یک آرگومان بسط می‌یابند. اگر خالی یا تعریف‌نشده باشند، نتیجه یک رشته خالی خواهد بود. اگر یک عنصر داشته باشند، به همان یک عنصر بسط پیدا می‌کنند. چنانچه بیش از یک عنصر داشته باشند، عناصر با فاصله (space) به هم متصل می‌شوند مگر اینکه متغیر یک متغیر مسیر (path variable) باشد که در آن صورت به جای فاصله از دونقطه (:) استفاده می‌گردد [3].

متغیرهای فیش همگی فهرست هستند و هنگام مقداردهی به عناصر تفکیک می‌شوند - این بدان معناست که تصمیم‌گیری در مورد استفاده یا عدم استفاده از نقل‌قول همراه با دستور set <> بسیار مهم است:

set foo 1 2 3 # a variable with three elements
rm $foo # runs the equivalent of `rm 1 2 3` - trying to delete three files: 1, 2 and 3.
rm "$foo" # runs `rm '1 2 3'` - trying to delete one file called '1 2 3'
set foo # an empty variable
rm $foo # runs `rm` without arguments
rm "$foo" # runs the equivalent of `rm ''`
set foo "1 2 3"
rm $foo # runs the equivalent of `rm '1 2 3'` - trying to delete one file
rm "$foo" # same thing

این رفتار برخلاف سایر پوسته‌ها است که عمل موسوم به «تفکیک کلمات» (Word Splitting) را انجام می‌دهند؛ یعنی متغیر را زمانی که در یک بسط استفاده می‌شود تفکیک می‌کنند. برای مثال در bash:

foo="1 2 3"
rm $foo # runs the equivalent of `rm 1 2 3`
rm "$foo" # runs the equivalent of `rm '1 2 3'`

این امر علت بروز خطاهای بسیار رایج در مواجهه با نام فایل‌های دارای فاصله در اسکریپت‌های بش است.

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

اگر متغیری به هیچ چیز بسط یابد، هر رشته دیگری که به آن چسبیده باشد را نیز خنثی می‌کند. برای اطلاعات بیشتر بخش ترکیب فهرست‌ها را ببینید.

در بیشتر مواقع، نقل‌قول نکردن متغیر کار درستی است. استثنا زمانی است که نیاز دارید اطمینان یابید متغیر حتی در صورت خالی بودن یا داشتن چند عنصر، دقیقاً به عنوان یک عنصر منتقل شود. این وضعیت اغلب در دستور test <> رخ می‌دهد:

set -l foo one two three
test -n $foo
# prints an error that it got too many arguments, because it was executed like
test -n one two three
test -n "$foo"
# works, because it was executed like
test -n "one two three"
[3]
برخلاف bash یا zsh که با نخستین نویسه متغیر $IFS (که معمولاً فاصله است) پیوند می‌دهند.

علامت $ می‌تواند به صورت چندباره نیز به کار رود، مانند نوعی عملگر «ارجاع‌زدایی» (مشابه * در C یا C++)؛ همان‌طور که در کد زیر مشاهده می‌شود:

set foo a b c
set a 10; set b 20; set c 30
for i in (seq (count $$foo))
    echo $$foo[$i]
end
# Output is:
# 10
# 20
# 30

عبارت $$foo[$i] یعنی «مقدار متغیری که نام آن توسط $foo[$i] مشخص شده است».

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

function print_var
    for arg in $argv
        echo Variable $arg is $$arg
    end
end
set -g foo 1 2 3
set -g bar a b c
print_var foo bar
# prints "Variable foo is 1 2 3" and "Variable bar is a b c"

البته متغیر باید از درون تابع قابل دسترسی باشد، بنابراین لازم است سراسری، جهانی (universal) یا صادرشده (exported) باشد. همچنین نباید با نام متغیری که درون تابع استفاده شده تداخل داشته باشد. اگر در آنجا $foo را متغیر محلی ساخته بودیم یا نام آن را «arg» گذاشته بودیم، کار نمی‌کرد.

هنگام استفاده از این قابلیت به همراه برش‌ها (slices)، برش‌ها از داخل به بیرون اعمال می‌شوند. عبارت $$foo[5] عنصر پنجم متغیر $foo را به عنوان نام متغیر استفاده می‌کند، به جای اینکه عنصر پنجم تمام متغیرهایی را بدهد که $foo به آن‌ها ارجاع دارد. برای حالت دوم، باید به صورت $$foo[1..-1][5] نوشته شود (تمامی عناصر $foo را بگیر، آن‌ها را به عنوان نام متغیرها به کار ببر، سپس عنصر پنجم آن‌ها را بده).

چند مثال دیگر:

set listone 1 2 3
set listtwo 4 5 6
set var listone listtwo
echo $$var
# Output is 1 2 3 4 5 6
echo $$var[1]
# Output is 1 2 3
echo $$var[2][3]
# $var[2] is listtwo, third element of that is 6, output is 6
echo $$var[..][2]
# The second element of every variable, so output is 2 5

همانند دیگر پوسته‌ها، می‌توانید مقدار یک متغیر را به عنوان یک دستور اجرا کنید.

> set -g EDITOR emacs
> $EDITOR foo # opens emacs, possibly the GUI version

اگر بخواهید به دستور درون متغیر یک آرگومان بدهید، باید آن آرگومان یک عنصر مجزا در فهرست باشد:

> set EDITOR emacs -nw
> $EDITOR foo # opens emacs in the terminal even if the GUI is installed
> set EDITOR "emacs -nw"
> $EDITOR foo # tries to find a command called "emacs -nw"

همچنین مانند سایر پوسته‌ها، این قابلیت تنها برای دستورات، دستورات توکار و توابع کارایی دارد - برای کلیدواژه‌ها کار نخواهد کرد زیرا کلیدواژه‌ها اهمیت نحوی دارند.

برای نمونه، عبارت set if $if به شما امکان ساخت بلوک if را نمی‌دهد، و set cmd command اجازه استفاده به عنوان آذین‌گر command <> را نخواهد داد، بلکه تنها کاربردهایی مانند $cmd -q foo مجاز است.

یک جایگزینی دستور بسطی است که از خروجی یک دستور به عنوان آرگومان‌های دستور دیگر استفاده می‌کند. برای مثال:

echo $(pwd)

این عبارت دستور pwd <> را اجرا کرده، خروجی آن را گرفته (به طور دقیق‌تر آنچه به جریان خروجی استاندارد «stdout» نوشته است) و آن را به عنوان آرگومان به دستور echo <> می‌دهد. بنابراین دستور درونی (pwd) ابتدا اجرا شده و باید پیش از شروع به کار دستور بیرونی، کار خود را به پایان برساند.

اگر دستور درونی چندین خط چاپ کند، فیش هر خط جداگانه را به عنوان یک آرگومان مستقل به دستور بیرونی تحویل می‌دهد. برخلاف دیگر پوسته‌ها، از مقدار متغیر $IFS استفاده نمی‌شود [4]؛ فیش بر اساس خطوط جدید (newline) تفکیک را انجام می‌دهد.

جایگزینی‌های دستور را می‌توان درون نقل‌قول دوتایی نیز قرار داد:

echo "$(pwd)"

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

اگر خروجی به عنوان گام پایانی به دستورات string split یا string split0 <> پایپ شود، آن تفکیک‌ها به همان صورتی که ظاهر می‌شوند به کار می‌روند، به جای آنکه بر اساس خطوط تفکیک شوند.

فیش همچنین نوشتن جایگزینی دستور بدون علامت دلار را ممکن می‌سازد، مانند echo (pwd). این شیوه درون نقل‌قول دوتایی بسط نمی‌یابد (echo "(pwd)" عبارت (pwd) را چاپ خواهد کرد).

وضعیت خروج آخرین جایگزینی دستور اجراشده در متغیر status در دسترس است، البته در صورتی که این جایگزینی در بستر یک دستور set <> رخ دهد (بنابراین عبارت if set -l (something) بررسی می‌کند که آیا دستور something وضعیت درست برگردانده است یا خیر).

برای استفاده تنها از برخی خطوط خروجی، به بخش برش‌ها (slices) مراجعه کنید.

مثال‌ها:

# Outputs 'image.png'.
echo (basename image.jpg .jpg).png
# Convert all JPEG files in the current directory to the
# PNG format using the 'convert' program.
for i in *.jpg; convert $i (basename $i .jpg).png; end
# Set the ``data`` variable to the contents of 'data.txt'
# without splitting it into a list.
set data "$(cat data.txt)"
# Set ``$data`` to the contents of data, splitting on NUL-bytes.
set data (cat data | string split0)

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

grep fish myanimallist1 | wc -l

اما اگر به چندین مورد نیاز دارید یا دستور از ورودی استاندارد نمی‌خواند، «جایگزینی فرآیند» (process substitution) کارآمد خواهد بود. سایر پوسته‌ها این کار را با نحو foo <(bar) <(baz) انجام می‌دهند، و فیش از دستور psub <> استفاده می‌کند:

# Compare only the lines containing "fish" in two files:
diff -u (grep fish myanimallist1 | psub) (grep fish myanimallist2 | psub)

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

پوسته فیش محدودیتی پیش‌فرض به میزان ۱ گیبی‌بایت (1 GiB) برای داده‌هایی که در جایگزینی دستور می‌خواند در نظر گرفته است. اگر این حد فراتر رود، کل دستور (تمام آن، نه فقط جایگزینی دستور - یعنی دستور بیرونی اصلاً اجرا نخواهد شد) شکست خورده و $status روی مقدار 122 تنظیم می‌شود. این امر به این دلیل است که جایگزینی دستور نتواند موجب اتمام حافظه سیستم شود، زیرا سیستم‌عامل شما معمولاً محدودیت بسیار پایین‌تری دارد و خواندن بیش از آن بی‌فایده و زیان‌بار خواهد بود. این محدودیت را می‌توان با متغیر fish_read_limit تغییر داد (مقدار 0 به معنای نبود محدودیت است). این محدودیت همچنین بر دستور read <> اثر می‌گذارد.

[4]
یک استثنا: خالی قرار دادن متغیر $IFS تفکیک خطوط را غیرفعال می‌کند. این شیوه منسوخ شده و بهتر است از string split <> استفاده کنید.

آکولادها می‌توانند برای نوشتن فهرست‌های جداشده با کاما به کار روند. آن‌ها به گونه‌ای بسط داده می‌شوند که هر عنصر به یک پارامتر جدید تبدیل شده و رشته‌های پیرامونی به آن متصل می‌گردند. این قابلیت برای صرفه‌جویی در تایپ و نیز جداسازی نام متغیر از متن مجاور بسیار مفید است.

مثال‌ها:

> echo input.{c,h,txt}
input.c input.h input.txt
# Move all files with the suffix '.c' or '.h' to the subdirectory src.
> mv *.{c,h} src/
# Make a copy of `file` at `file.bak`.
> cp file{,.bak}
> set -l dogs hot cool cute "good "
> echo {$dogs}dog
hotdog cooldog cutedog good dog

اگر بین آکولادها علامت «,» یا بسط متغیر وجود نداشته باشد، بسط داده نخواهند شد:

# This {} isn't special
> echo foo-{}
foo-{}
# This passes "HEAD@{2}" to git
> git reset --hard HEAD@{2}
> echo {{a,b}}
{a} {b} # because the inner brace pair is expanded, but the outer isn't.

اگر پس از بسط، چیزی میان آکولادها باقی نماند، آن آرگومان به کلی حذف می‌شود (بخش ترکیب فهرست‌ها را ببینید):

> echo foo-{$undefinedvar}
# Output is an empty line, like a bare `echo`.

اگر بین یک آکولاد و یک کاما، یا بین دو کاما چیزی وجود نداشته باشد، به عنوان یک عنصر خالی تفسیر می‌شود:

> echo {,,/usr}/bin
/bin /bin /usr/bin

برای استفاده از «,» به عنوان یک عنصر عادی، آن را نقل‌قول کنید یا با نویسه گریز بنویسید.

نخستین کاراکتر از توکن یک دستور هرگز به عنوان بسط آکولاد تفسیر نمی‌شود، زیرا نشانه شروع یک دستور مرکب (compound statement) است:

> {echo hello, && echo world}
hello,
world

پوسته فیش فهرست‌ها را همانند بسط‌های آکولاد بسط می‌دهد:

>_ set -l foo x y z
>_ echo 1$foo
# Any element of $foo is combined with the "1":
1x 1y 1z
>_ echo {good,bad}" apples"
# Any element of the {} is combined with the " apples":
good apples bad apples
# Or we can mix the two:
>_ echo {good,bad}" "$foo
good x bad x good y bad y good z bad z

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

دو فهرست در تمامی ترکیبات ممکن بسط می‌یابند - هر عنصر از فهرست اول با هر عنصر از فهرست دوم:

>_ set -l a x y z; set -l b 1 2 3
>_ echo $a$b # same as {x,y,z}{1,2,3}
x1 y1 z1 x2 y2 z2 x3 y3 z3

پیامد این رفتار آن است که اگر یک فهرست عنصری نداشته باشد، رشته با صفر عنصر ترکیب می‌شود و در نتیجه کل توکن حذف خواهد شد!

>_ set -l c # <- this list is empty!
>_ echo {$c}word
# Output is an empty line - the "word" part is gone

این ویژگی می‌تواند بسیار مفید باشد. برای مثال اگر می‌خواهید تمام فایل‌های موجود در تمامی دایرکتوری‌های متغیر PATH را بررسی کنید:

for file in $PATH/*

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

گاهی ممکن است این رفتار ناخواسته باشد، به ویژه ناپدید شدن توکن‌ها پس از بسط. در چنین مواردی باید متغیرها را درون نقل‌قول دوتایی قرار دهید - مانند echo "$c"word.

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

>_ set b 1 2 3
>_ echo (echo x)$b
x1 x2 x3
>_ echo (printf '%s' '')banana
# the printf prints nothing, so this is nothing times "banana",
# which is nothing.
>_ echo (printf '%s\n' '')banana
# the printf prints a newline,
# so the command substitution expands to an empty string,
# so this is `''banana`
banana
>_ echo "$(printf '%s' '')"banana
# quotes mean this is one argument, the banana stays

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

# Make $var a list of four elements
set var one two three four
# Print the second:
echo $var[2]
# prints "two"
# or print the first three:
echo $var[1..3]
# prints "one two three"

درون براکت‌های نمایه، فیش بازه‌هایی به شکل a..b را درک می‌کند (که در آن «a» و «b» نمایه هستند). آن‌ها به توالی نمایه‌ها از a تا b بسط می‌یابند (یعنی a a+1 a+2 ... b)؛ اگر b بزرگتر باشد صعودی و اگر a بزرگتر باشد نزولی خواهند بود. نمایه‌های منفی نیز قابل استفاده‌اند - این نمایه‌ها از انتهای فهرست محاسبه می‌شوند، بنابراین -1 آخرین عنصر است و -2 عنصر یکی مانده به آخر. اگر نمایه‌ای وجود نداشته باشد، بازه تا نزدیک‌ترین نمایه ممکن تنظیم و محدود (clamp) می‌شود.

اگر یک فهرست ۵ عنصر داشته باشد، نمایه‌ها از ۱ تا ۵ هستند؛ بنابراین بازه 2..16 تنها از عنصر ۲ تا ۵ پیش می‌رود.

اگر انتهای بازه منفی باشد، مسیر بازه همیشه صعودی است؛ بنابراین 2..-2 از عنصر ۲ تا ۴ می‌رود، و 2..-16 به هیچ کجا نمی‌رود چون هیچ راهی برای رفتن صعودی از عنصر دوم به عنصری که وجود ندارد وجود ندارد. اگر ابتدای بازه منفی باشد، مسیر همیشه نزولی است؛ بنابراین -2..1 از عنصر ۴ تا ۱ می‌رود، و -16..2 به هیچ کجا نمی‌رود چون راهی برای رفتن نزولی از عنصری ناموجود به عنصر دوم وجود ندارد.

نبود نمایه آغازین در یک بازه به طور پیش‌فرض برابر با ۱ در نظر گرفته می‌شود. این حالت در صورتی مجاز است که بازه، نخستین عبارت نمایه‌ای در توالی باشد. به همین ترتیب، نبود نمایه پایانی به طور پیش‌فرض برابر با -1 در نظر گرفته می‌شود که برای آخرین نمایه در توالی مجاز است.

استفاده از چندین بازه نیز امکان‌پذیر است که با فاصله از هم جدا می‌شوند.

چند مثال:

echo (seq 10)[1 2 3]
# Prints: 1 2 3
# Limit the command substitution output
echo (seq 10)[2..5]
# Uses elements from 2 to 5
# Output is: 2 3 4 5
echo (seq 10)[7..]
# Prints: 7 8 9 10
# Use overlapping ranges:
echo (seq 10)[2..5 1..3]
# Takes elements from 2 to 5 and then elements from 1 to 3
# Output is: 2 3 4 5 1 2 3
# Reverse output
echo (seq 10)[-1..1]
# Uses elements from the last output line to
# the first one in reverse direction
# Output is: 10 9 8 7 6 5 4 3 2 1
# The command substitution has only one line,
# so these will result in empty output:
echo (echo one)[2..-1]
echo (echo one)[-3..1]

همین قاعده هنگام تنظیم یا بسط متغیرها نیز کار می‌کند:

# Reverse path variable
set PATH $PATH[-1..1]
# or
set PATH[-1..1] $PATH
# Use only n last items of the PATH
set n -3
echo $PATH[$n..-1]

می‌توان از متغیرها به عنوان نمایه برای بسط متغیرها استفاده کرد، مانند:

set index 2
set letters a b c d
echo $letters[$index] # returns 'b'

با این حال، استفاده از متغیرها به عنوان نمایه برای جایگزینی دستور در حال حاضر پشتیبانی نمی‌شود:

echo (seq 5)[$index] # This won't work
set sequence (seq 5) # It needs to be written on two lines like this.
echo $sequence[$index] # returns '2'

هنگام استفاده از بسط غیرمستقیم متغیر با چندین علامت $ ($$name)، باید تمام نمایه‌ها را تا رسیدن به متغیری که می‌خواهید برش بزنید مشخص کنید:

> set -l list 1 2 3 4 5
> set -l name list
> echo $$name[1]
1 2 3 4 5
> echo $$name[1..-1][1..3] # or $$name[1][1..3], since $name only has one element.
1 2 3

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

ls ~/Music # lists my music directory
echo ~root # prints root's home directory, probably "/root"

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

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

  • جایگزینی‌های دستور
  • بسط‌های متغیر
  • بسط‌های براکت و آکولاد
  • بسط نویسه‌های عام (الگوهای تطبیق فایل)

بسط‌ها از راست به چپ انجام می‌شوند؛ بسط‌های تودرتوی براکت و جایگزینی‌های دستور از درون به بیرون اعمال می‌گردند.

مثال:

اگر دایرکتوری جاری حاوی فایل‌های «foo» و «bar» باشد، دستور echo a(ls){1,2,3} خروجی abar1 abar2 abar3 afoo1 afoo2 afoo3 را تولید خواهد کرد.

به عنوان جمع‌بندی، در اینجا یک مرجع سریع برای عملگرهای فیش و تمامی نمادهای ویژه‌ای که به کار می‌برد آورده شده است:

نماد مفهوم مثال
$ بسط متغیر echo $foo
$() و () جایگزینی دستور cat (grep foo bar) یا cat $(grep foo bar)
< و > تغییرمسیر، مانند command > file git shortlog -nse . > authors
| پایپ (لوله)، اتصال دو یا چند دستور foo | grep bar | grep baz
; پایان دستور، به جای خط جدید command1; command2
& اجرا در پس‌زمینه sleep 5m &
{} بسط آکولاد ls {/usr,}/bin
&& و || ترکیب‌کننده‌ها mkdir foo && cd foo یا rm foo || exit
* و ** نویسه‌های عام cat *.fish یا count **.jpg
\\ گریزدهی (Escaping) echo foo\nbar یا echo \$foo
'' و "" نقل‌قول rm "file with spaces" یا echo '$foo'
~ بسط دایرکتوری خانگی ls ~/ یا ls ~root/
# توضیحات و کامنت‌ها echo Hello # this isn't printed

متغیرها روشی برای ذخیره داده‌ها و انتقال آن‌ها به بخش‌های مختلف هستند. این متغیرها می‌توانند صرفاً درون پوسته استفاده شوند یا «صادر» (exported) گردند تا کپی‌ای از آن‌ها در اختیار هر دستور خارجی که توسط پوسته اجرا می‌شود قرار گیرد. به یک متغیر صادرشده اصطلاحاً «متغیر محیطی» (environment variable) گفته می‌شود.

برای مقداردهی یک متغیر، از دستور set <> استفاده کنید. نام یک متغیر نمی‌تواند خالی باشد و تنها می‌تواند شامل حروف، ارقام و زیرخط (underscore) باشد. نام متغیر می‌تواند با هر یک از این نویسه‌ها شروع شده یا پایان یابد.

مثال:

برای مقداردهی متغیر smurf_color با مقدار blue، از دستور set smurf_color blue استفاده کنید.

پس از مقداردهی یک متغیر، می‌توانید از مقدار آن درون پوسته از طریق بسط متغیر بهره ببرید.

مثال:

set smurf_color blue
echo Smurfs are usually $smurf_color
set pants_color red
echo Papa smurf, who is $smurf_color, wears $pants_color pants

بنابراین شما یک متغیر را با set مقداردهی کرده و با استفاده از علامت $ همراه با نام آن، مورد استفاده قرار می‌دهید.

تمامی متغیرها در فیش دارای یک دامنه (scope) هستند. برای نمونه می‌توانند سراسری (global) یا برای یک تابع یا بلوک، محلی (local) باشند:

# This variable is global, we can use it everywhere.
set --global name Patrick
# This variable is local, it will not be visible in a function we call from here.
set --local place "at the Krusty Krab"
function local
    # This can find $name, but not $place
    echo Hello this is $name $place
    # This variable is local, it will not be available
    # outside of this function
    set --local instrument mayonnaise
    echo My favorite instrument is $instrument
    # This creates a local $name, and won't touch the global one
    set --local name Spongebob
    echo My best friend is $name
end
local
# Will print:
# Hello this is Patrick
# My favorite instrument is mayonnaise
# My best friend is Spongebob
echo $name, I am $place and my instrument is $instrument
# Will print:
# Patrick, I am at the Krusty Krab and my instrument is

در فیش چهار نوع دامنه برای متغیرها وجود دارد: متغیرهای جهانی (universal)، سراسری (global)، تابعی (function) و محلی (local).

  • متغیرهای جهانی (Universal) بین تمامی نشست‌های فیش متعلق به یک کاربر روی یک رایانه به اشتراک گذاشته می‌شوند. این متغیرها روی دیسک ذخیره شده و حتی پس از راه‌اندازی مجدد سیستم پایدار می‌مانند.
  • متغیرهای سراسری (Global) مختص نشست جاری فیش هستند. این متغیرها را می‌توان با درخواست صریح دستور set -e حذف کرد.
  • متغیرهای تابعی (Function) مختص تابعی هستند که در حال حاضر در حال اجرا است. هنگامی که تابع جاری پایان می‌یابد، این متغیرها پاک می‌شوند (از دامنه خارج می‌شوند). خارج از یک تابع، این متغیرها از دامنه خارج نمی‌شوند.
  • متغیرهای محلی (Local) مختص بلوک جاری از دستورات هستند و زمانی که آن بلوک مشخص به پایان می‌رسد، به طور خودکار پاک می‌شوند. یک بلوک از دستورات، مجموعه‌ای از دستورات است که با یکی از دستورات for، while، if، function، begin یا switch آغاز شده و با دستور end پایان می‌یابد. خارج از یک بلوک، این دامنه همانند دامنه تابعی رفتار می‌کند.

متغیرها را می‌توان با سوییچ‌های -U یا --universal صراحتاً جهانی، با -g یا --global سراسری، با -f یا --function با دامنه تابع، و با -l یا --local برای بلوک جاری محلی تعریف کرد. قواعد تعیین دامنه هنگام ایجاد یا به‌روزرسانی یک متغیر به این صورت است:

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

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

مثال:

کاربردهای گوناگونی برای دامنه‌های مختلف وجود دارد.

معمولاً درون توابع باید از دامنه محلی استفاده کنید:

function something
    set -l file /path/to/my/file
    if not test -e "$file"
        set file /path/to/my/otherfile
    end
end
# or
function something
    if test -e /path/to/my/file
        set -f file /path/to/my/file
    else
        set -f file /path/to/my/otherfile
    end
end

اگر می‌خواهید مقداری را در config.fish تنظیم کنید، یا چیزی را درون یک تابع مقداردهی کنید تا برای بقیه مدت نشست در دسترس بماند، دامنه سراسری گزینه مناسبی است:

# Don't shorten the working directory in the prompt
set -g fish_prompt_pwd_dir_length 0
# Set my preferred cursor style:
function setcursors
   set -g fish_cursor_default block
   set -g fish_cursor_insert line
   set -g fish_cursor_visual underscore
end
# Set my language
set -gx LANG de_DE.UTF-8

در اینجا مقایسه‌ای بین متغیرهای محلی و متغیرهای با دامنه تابع آورده شده است:

function test-scopes
    begin
        # This is a nice local scope where all variables will die
        set -l pirate 'There be treasure in them thar hills'
        set -f captain Space, the final frontier
        # If no variable of that name was defined, it is function-local.
        set gnu "In the beginning there was nothing, which exploded"
    end
    # This will not output anything, since the pirate was local
    echo $pirate
    # This will output the good Captain's speech
    # since $captain had function-scope.
    echo $captain
    # This will output Sir Terry's wisdom.
    echo $gnu
end

هنگامی که یک تابع، تابع دیگری را فراخوانی می‌کند، متغیرهای محلی تابع اول برای دومی قابل مشاهده نیستند:

function shiver
    set phrase 'Shiver me timbers'
end
function avast
    set --local phrase 'Avast, mateys'
    # Calling the shiver function here can not
    # change any variables in the local scope
    # so phrase remains as we set it here.
    shiver
    echo $phrase
end
avast
# Outputs "Avast, mateys"

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

اگر مایلید متغیری را صرفاً برای اجرای یک دستور منفرد بازنویسی (override) کنید، می‌توانید از عبارات «var=val» پیش از نام دستور استفاده نمایید:

# Call git status on another directory
# (can also be done via `git -C somerepo status`)
GIT_DIR=somerepo git status

برخلاف برخی پوسته‌های دیگر، فیش ابتدا متغیر را تنظیم کرده و سپس سایر بسط‌های خط فرمان را انجام می‌دهد؛ بنابراین:

set foo banana
foo=gagaga echo $foo
# prints gagaga, while in other shells it might print "banana"

امکان تعریف چندین عنصر از طریق بسط آکولاد نیز فراهم است:

# Call bash with a reasonable default path.
PATH={/usr,}/{s,}bin bash

یا از طریق یک الگوی عام (glob):

# Run vlc on all mp3 files in the current directory
# If no file exists it will still be run with no arguments
mp3s=*.mp3 vlc $mp3s

برخلاف پوسته‌های دیگر، این شیوه مانع جستجوی دستورات (نام‌های مستعار یا مشابه آن) نمی‌شود. فراخوانی یک دستور پس از تنظیم متغیر بازنویسی، دقیقاً منجر به اجرای همان دستور خواهد شد.

این نحو از نسخه ۳.۱ فیش پشتیبانی می‌شود.

متغیرهای جهانی متغیرهایی هستند که میان تمامی نشست‌های فیش کاربر بر روی رایانه به اشتراک گذاشته می‌شوند. تمامی تغییرات در متغیرهای جهانی پایدار بوده و بی‌درنگ در تمامی نشست‌های فیش منتشر می‌شوند.

متغیرهای جهانی در فایل .config/fish/fish_variables ذخیره می‌گردند. این فایل را مستقیماً ویرایش نکنید، زیرا ممکن است تغییرات شما بازنویسی شود. در عوض، متغیرها را از طریق اسکریپت‌های فیش یا با استفاده تعاملی از فیش ویرایش نمایید.

از افزودن مقدار به متغیرهای جهانی در فایل config.fish خودداری کنید، چرا که در این صورت با باز شدن هر نمونه پوسته جدید، این متغیرها طولانی‌تر خواهند شد. به جای آن، یک بار آن‌ها را در خط فرمان تنظیم کنید.

متغیرها در فیش می‌توانند صادر (export) شوند تا توسط هر دستوری که توسط فیش راه‌اندازی می‌شود به ارث برسند. به طور خاص، این امر برای متغیرهایی که جهت پیکربندی دستورات خارجی استفاده می‌شوند (مانند PAGER یا GOPATH) و همچنین متغیرهایی که حاوی تنظیمات عمومی سیستم هستند (مانند PATH یا LANGUAGE) ضروری است. اگر یک دستور خارجی نیاز دارد از یک متغیر باخبر باشد، آن متغیر باید صادر شود. متغیرهای صادرشده اغلب «متغیرهای محیطی» نیز نامیده می‌شوند.

این اصل برای خود فیش نیز صادق است - هنگامی که راه‌اندازی می‌شود، متغیرهای محیطی را از والد خود (معمولاً ترمینال) دریافت می‌کند. این متغیرها معمولاً شامل تنظیمات سیستمی مانند PATH و متغیرهای محلی‌سازی (locale) هستند.

متغیرها را می‌توان با سوییچ -x یا --export صراحتاً صادر کرد، یا با سوییچ -u یا --unexport از حالت صادرشده خارج ساخت. قواعد صادر کردن هنگام تنظیم متغیر شبیه به قواعد دامنه متغیرهاست - هنگامی که گزینه‌ای ارسال شود اعمال می‌گردد، در غیر این صورت وضعیت فعلی متغیر استفاده می‌شود. اگر گزینه‌ای مشخص نشود و متغیر از قبل وجود نداشته باشد، صادر نخواهد شد.

بر اساس یک قرارداد نام‌گذاری، متغیرهای صادرشده با حروف بزرگ و متغیرهای صادرنشده با حروف کوچک نوشته می‌شوند.

برای نمونه:

set -gx ANDROID_HOME ~/.android # /opt/android-sdk
set -gx CDPATH . ~ (test -e ~/Videos; and echo ~/Videos)
set -gx EDITOR emacs -nw
set -gx GOPATH ~/dev/go
set -gx GTK2_RC_FILES "$XDG_CONFIG_HOME/gtk-2.0/gtkrc"
set -gx LESSHISTFILE "-"

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

پوسته فیش می‌تواند یک فهرست (یا در صورت تمایل یک «آرایه») از چندین رشته را درون یک متغیر ذخیره کند:

> set mylist first second third
> printf '%s\n' $mylist # prints each element on its own line
first
second
third

برای دسترسی به یک عنصر از فهرست، از نمایه (اندیس) آن عنصر درون براکت استفاده کنید، مانند:

echo $PATH[3]

نمایه‌های فهرست در فیش از ۱ آغاز می‌شوند، نه از ۰ مانند سایر زبان‌ها. علت این است که نیاز به کسر عدد ۱ را کاهش می‌دهد و بسیاری از ابزارهای رایج یونیکس مانند seq با این شیوه بهتر کار می‌کنند (seq 5 اعداد ۱ تا ۵ را چاپ می‌کند، نه ۰ تا ۵). نمایه نامعتبر بدون هشدار نادیده گرفته شده و مقداری برنمی‌گرداند (حتی رشته خالی برنمی‌گرداند، یعنی هیچ آرگومانی ارسال نمی‌شود).

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

for i in $PATH
    echo $i is in the path
end

این دستور تمام دایرکتوری‌های موجود در PATH را به صورت جداگانه پیمایش کرده و برای هر کدام خطی چاپ می‌کند که نشان می‌دهد در مسیر قرار دارد.

برای ایجاد متغیر smurf که حاوی آیتم‌های blue و small باشد، بنویسید:

set smurf blue small

همچنین امکان مقداردهی یا حذف تک‌تک عناصر یک فهرست وجود دارد:

# Set smurf to be a list with the elements 'blue' and 'small'
set smurf blue small
# Change the second element of smurf to 'evil'
set smurf[2] evil
# Erase the first element
set -e smurf[1]
# Output 'evil'
echo $smurf

اگر هنگام بسط یا مقداردهی به یک متغیر فهرستی، نمایه منفی مشخص کنید، نمایه از انتهای فهرست محاسبه می‌شود. برای مثال، نمایه -1 آخرین عنصر فهرست است:

> set fruit apple orange banana
> echo $fruit[-1]
banana
> echo $fruit[-2..-1]
orange
banana
> echo $fruit[-1..1] # reverses the list
banana
orange
apple

همان‌طور که مشاهده می‌کنید، می‌توانید از بازه‌ای از نمایه‌ها استفاده کنید؛ برای جزئیات به بخش برش‌ها (slices) مراجعه نمایید.

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

هنگامی که یک فهرست به عنوان متغیر محیطی صادر می‌شود، بسته به اینکه متغیر مسیر (path variable) باشد یا خیر، با فاصله یا با دونقطه تفکیک می‌گردد:

> set -x smurf blue small
> set -x smurf_PATH forest mushroom
> env | grep smurf
smurf=blue small
smurf_PATH=forest:mushroom

فیش به طور خودکار از تمامی متغیرهای محیطی که نامشان به PATH ختم می‌شود (مانند PATH، CDPATH یا MANPATH)، از طریق تفکیک بر اساس دونقطه، فهرست ایجاد می‌کند. متغیرهای دیگر به طور خودکار تفکیک نمی‌شوند.

فهرست‌ها را می‌توان با دستورات count <> یا contains <> بررسی و بازرسی کرد:

> count $smurf
2
> contains blue $smurf
# blue was found, so it exits with status 0
# (without printing anything)
> echo $status
0
> contains -i blue $smurf
1

ویژگی عالی فهرست‌ها این است که به دستورات به صورت هر عنصر در قالب یک آرگومان مستقل منتقل می‌شوند؛ بنابراین به محض مقداردهی فهرست، می‌توانید آن را ارسال کنید:

set -l grep_args -r "my string"
grep $grep_args . # will run the same as `grep -r "my string"` .

برخلاف پوسته‌های دیگر، فیش «تفکیک کلمات» (word splitting) را انجام نمی‌دهد - عناصر درون فهرست همان‌گونه که هستند باقی می‌مانند، حتی اگر شامل فاصله یا تب باشند.

یک فهرست مهم متغیر $argv است که شامل آرگومان‌های ارسالی به یک تابع یا اسکریپت می‌باشد. برای نمونه:

function myfunction
    echo $argv[1]
    echo $argv[3]
end

این تابع هر آرگومانی را که دریافت کند می‌گیرد و آرگومان‌های اول و سوم را چاپ می‌کند:

> myfunction first second third
first
third
> myfunction apple cucumber banana
apple
banana

این موضوع آرگومان‌های مکانی (positional arguments) را پوشش می‌دهد، اما ابزارهای خط فرمان معمولاً گزینه‌ها و فلگ‌های گوناگونی دریافت می‌کنند و $argv آن‌ها را درهم‌آمیخته با آرگومان‌های مکانی نگه می‌دارد. روش معمول مدیریت آرگومان در یونیکس از گزینه‌های کوتاه (-h، و همچنین گروه‌بندی‌شده مانند ls -lah)، گزینه‌های بلند (--help) و امکان آرگومان گرفتن این گزینه‌ها (--color=auto یا --position anywhere یا complete -C"git ") و همچنین جداکننده -- برای مشخص کردن پایان گزینه‌ها پشتیبانی می‌کند. مدیریت دستی تمام این موارد دشوار و مستعد خطاست.

یک روش قوی‌تر برای مدیریت گزینه‌ها دستور توکار argparse <> است که گزینه‌های تعریف‌شده را بررسی کرده و درون متغیرهای مختلف قرار می‌دهد، به طوری که تنها آرگومان‌های مکانی در $argv باقی می‌مانند. در اینجا یک مثال ساده آورده شده است:

function mybetterfunction
    # We tell argparse about -h/--help and -s/--second
    # - these are short and long forms of the same option.
    # The "--" here is mandatory,
    # it tells it from where to read the arguments.
    argparse h/help s/second -- $argv
    # exit if argparse failed because
    # it found an option it didn't recognize
    # - it will print an error
    or return
    # If -h or --help is given, we print a little help text and return
    if set -ql _flag_help
        echo "mybetterfunction [-h|--help] [-s|--second] [ARGUMENT ...]"
        return 0
    end
    # If -s or --second is given, we print the second argument,
    # not the first and third.
    # (this is also available as _flag_s because of the short version)
    if set -ql _flag_second
        echo $argv[2]
    else
        echo $argv[1]
        echo $argv[3]
    end
end

گزینه‌ها از $argv حذف خواهند شد، بنابراین اکنون $argv[2] دومین آرگومان مکانی است:

> mybetterfunction first -s second third
second

برای اطلاعات بیشتر درباره argparse، از جمله نحوه مدیریت آرگومان‌های گزینه‌ها، مستندات argparse <> را ببینید.

متغیرهای مسیر (Path variables) نوع خاصی از متغیرها هستند که برای پشتیبانی از فهرست‌های مسیر تفکیک‌شده با دونقطه به کار می‌روند؛ از جمله PATH، CDPATH، MANPATH، PYTHONPATH، LANGUAGE (برای بومی‌سازی <>) و غیره. تمام متغیرهایی که نامشان به «PATH» ختم می‌شود (حساس به بزرگی و کوچکی حروف)، به صورت پیش‌فرض متغیر مسیر می‌شوند.

متغیرهای PATH مانند فهرست‌های عادی رفتار می‌کنند، با این تفاوت که به طور ضمنی بر اساس دونقطه به هم پیوند خورده یا تفکیک می‌شوند.

set MYPATH 1 2 3
echo "$MYPATH"
# 1:2:3
set MYPATH "$MYPATH:4:5"
echo $MYPATH
# 1 2 3 4 5
echo "$MYPATH"
# 1:2:3:4:5

متغیرهای مسیر هنگام صادر شدن نیز در قالب دونقطه صادر می‌شوند؛ بنابراین با اجرای set -x MYPATH 1 2 3، دستورات خارجی آن را به صورت 1:2:3 خواهند دید.

> set -gx MYPATH /bin /usr/bin /sbin
> env | grep MYPATH
MYPATH=/bin:/usr/bin:/sbin

این امر برای سازگاری با سایر ابزارهاست. یونیکس متغیرهایی با چندین عنصر ندارد؛ نزدیک‌ترین چیز به آن فهرست‌های تفکیک‌شده با دونقطه مانند PATH است. به دلایل واضح، این یعنی هیچ عنصری نمی‌تواند شامل نویسه : باشد.

متغیرها را می‌توان از طریق گزینه‌های --path و --unpath در دستور set به عنوان متغیر مسیر نشانه‌گذاری کرده یا از این حالت خارج ساخت.

می‌توانید با تغییر مقادیر برخی متغیرها، تنظیمات فیش را دگرگون سازید.

فهرستی از دایرکتوری‌ها که برای یافتن دستورات در آن‌ها جستجو می‌شود. این یک متغیر رایج یونیکس است که توسط سایر ابزارها نیز به کار می‌رود.
فهرستی از دایرکتوری‌ها که دستور توکار cd <> برای یافتن یک دایرکتوری جدید در آن‌ها جستجو می‌کند.
متغیرهای محلی‌سازی مانند LANG، LC_ALL، LC_MESSAGES، LC_NUMERIC و LC_TIME تنظیمات زبان را برای پوسته و زیربرنامه‌ها مشخص می‌کنند. برای اطلاعات بیشتر، بخش متغیرهای محلی‌سازی و زبان وضعیت را ببینید <#status-language>.
تعدادی متغیر که با پیشوندهای fish_color و fish_pager_color آغاز می‌شوند. برای اطلاعات بیشتر، بخش متغیرهای تغییر رنگ‌های برجسته‌سازی را ببینید <#variables-color>.
اگر این متغیر روی 0 تنظیم شود، فیش توالی‌های رنگی ۲۴ بیتی (true-color) RGB را به عنوان خروجی ارسال نخواهد کرد؛ بلکه نزدیک‌ترین رنگ در پالت ۲۵۶ رنگ (یا پالت ۱۶ رنگ در صورتی که fish_term256 برابر با 0 باشد) را استفاده می‌کند. دستور set_color <> را نیز ببینید. مقدار پیش‌فرض 1 است، اما به دلایل تاریخی، فیش در برخی از ترمینال‌هایی که پشتیبانی نکردن آن‌ها از رنگ‌های واقعی مشخص است، به صورت پیش‌فرض رفتاری مشابه مقدار 0 خواهد داشت.
اگر این متغیر و همچنین fish_term24bit هر دو روی 0 تنظیم شوند، رنگ‌های RGB به پالت ۱۶ رنگ تنزل داده می‌شوند. همچنین اگر این متغیر 0 باشد، دستورات set_color <> مانند set_color ff0000 red رنگ نام‌گذاری‌شده را ترجیح خواهند داد.
عرض محاسبه‌شده برای نویسه‌های با عرض مبهم (ambiguous-width) را کنترل می‌کند. اگر ترمینال شما این نویسه‌ها را با عرض تک‌سلولی (حالت معمول) رندر می‌کند باید روی 1، و اگر با عرض دوسلولی رندر می‌کند باید روی 2 تنظیم شود.
تعیین می‌کند که آیا فیش عرض ایموجی‌ها را ۲ سلول فرض کند یا ۱ سلول. این تنظیم از آن جهت لازم است که در استاندارد یونیکد ۹ مقدار صحیح از ۱ به ۲ تغییر یافت و برخی از ترمینال‌ها ممکن است از آن آگاه نباشند. اگر اشکالات بصری مربوط به ایموجی‌ها (یا سایر نویسه‌های «ویژه») مشاهده کردید، این مقدار را تنظیم کنید. پیش‌فرض آن 2 است.
فعال بودن پیشنهادهای خودکار autosuggestions <#autosuggestions> را کنترل می‌کند. برای غیرفعال‌سازی مقدار آن را 0 و برای فعال‌سازی مقداری دیگر تعیین کنید. به صورت پیش‌فرض فعال است.
اگر این مقدار روی 1 تنظیم شود، فیش اعلان‌های خط فرمان را با آرگومان --final-rendering پیش از اجرای خط فرمان بازترسیم می‌کند، که امکان تغییر آن را قبل از فرستاده شدن به تاریخچه اسکرول (scrollback) فراهم می‌سازد. این متغیر اعلان‌های گذرا (transient prompts) را فعال می‌کند <#transient-prompt>.
تعیین می‌کند که آیا فیش در هنگام تغییر اندازه ترمینال، باید خط فرمان را مجدداً ترسیم کند یا خیر. در ترمینال‌هایی که متن را مجدداً سازماندهی می‌کنند (reflow)، این ویژگی باید غیرفعال شود. برای فعال‌سازی مقدار را روی 1 و برای غیرفعال‌سازی روی مقداری دیگر قرار دهید.
نام تابعی که کلیدهای میانبر ویرایشگر خط فرمان را تنظیم می‌کند <#editor>.
مدت زمانی (بر حسب میلی‌ثانیه) را تعیین می‌کند که فیش پس از دریافت نویسه Escape، برای دریافت کلید بعدی منتظر می‌ماند تا فشردن کلید Escape را از ابتدای یک توالی گریز (escape sequence) تمیز دهد. مقدار پیش‌فرض 30 میلی‌ثانیه است. افزایش آن زمان تأخیر را بالا می‌برد اما فشردن Escape به جای Alt را برای کلیدهای ترکیبی Alt+character ممکن می‌سازد. برای اطلاعات بیشتر، فصل مربوطه را در مستندات bind ببینید <#cmd-bind-escape>.
مدت زمانی را تعیین می‌کند که فیش پس از دریافت کلیدی که بخشی از یک توالی طولانی‌تر است منتظر کلید بعدی می‌ماند تا ابهام را برطرف کند. برای نمونه اگر \cx\ce را برای باز کردن ویرایشگر نگاشت کرده باشید، فیش این مدت زمان را برای دریافت ctrl-e پس از ctrl-x صبر می‌کند. در صورت پایان مهلت، با آن به عنوان ctrl-x رفتار می‌کند (که به طور پیش‌فرض خط فرمان جاری را در حافظه کلیپ‌بورد کپی می‌کند). توالی‌های کلید را نیز ببینید <#interactive-key-sequences>.
محل‌هایی را که فیش برای تکمیل خودکار جستجو می‌کند تعیین می‌نماید. هنگام تلاش برای تکمیل خودکار یک دستور، فیش در دایرکتوری‌های مشخص‌شده در این متغیر به دنبال فایل‌ها می‌گردد.
کنترل می‌کند که آیا انتخاب متن شامل نویسه زیر مکان‌نما می‌شود یا خیر (بخش کپی و پیست را ببینید <#killring>).
محل جستجوی فیش برای توابع را مشخص می‌کند. هنگام بارگذاری خودکار یک تابع، فیش فایل‌ها را درون این دایرکتوری‌ها جستجو خواهد کرد.
پیام خوشامدگویی که هنگام راه‌اندازی چاپ می‌شود. این پیام توسط تابعی با همین نام چاپ می‌شود که برای تغییرات پیچیده‌تر می‌توان آن را بازنویسی کرد (دستور funced <> را ببینید).
نام نشست تاریخچه جاری. در صورت تنظیم، تمامی دستورات بعدی درون یک نشست تعاملی فیش در فایلی مجزا که با مقدار این متغیر مشخص می‌شود ثبت خواهند شد. در صورت عدم تنظیم، نام نشست پیش‌فرض «fish» استفاده می‌شود. اگر روی یک رشته خالی تنظیم شود، تاریخچه روی دیسک ذخیره نخواهد شد (اما همچنان درون نشست تعاملی در دسترس است).
در صورت مقداردهی و خالی نبودن، باعث می‌شود فیش دستورات را پیش از اجرا چاپ کند، مشابه set -x در بش. خروجی ردگیری به مسیری که توسط گزینه --debug-output یا متغیر FISH_DEBUG_OUTPUT مشخص شده نوشته می‌شود. به طور پیش‌فرض به خروجی خطای استاندارد (stderr) ارسال می‌گردد. تنظیم آن روی all همچنین اجرای کلیدهای میانبر، گرداننده‌های رویداد و توابع اعلان خط فرمان و عنوان پنجره را نیز ردگیری می‌کند.
دسته‌بندی‌های اشکال‌زدایی را که fish برای خروجی فعال می‌سازد کنترل می‌کند، مشابه گزینه --debug.
فایلی را برای هدایت خروجی اشکال‌زدایی به آن مشخص می‌کند.
فهرستی از دایرکتوری‌ها که به ابتدای PATH افزوده می‌شوند. این می‌تواند یک متغیر جهانی (universal) باشد.
ماسک ایجاد فایل جاری. روش ارجح برای تغییر متغیر umask استفاده از تابع umask <> است. تلاش برای تنظیم umask روی مقداری نامعتبر همواره با شکست مواجه می‌شود.
در صورت تنظیم، این رشته به طور خودکار به ابتدای اعلان خط فرمان چپ افزوده می‌شود. این یک متغیر محیطی استاندارد است که ممکن است توسط ابزارهایی مانند run0 در systemd تنظیم شود تا نشست‌های ویژه پوسته را نشان دهد.
در صورت تنظیم، این رشته به طور خودکار به انتهای اعلان خط فرمان چپ افزوده می‌شود. این یک متغیر محیطی استاندارد است که ممکن است توسط ابزارهایی مانند run0 در systemd تنظیم شود تا نشست‌های ویژه پوسته را نشان دهد.
در صورت تنظیم، این رشته هنگام شروع به کار یک پوسته تعاملی، پس از پیام خوشامدگویی نمایش داده می‌شود. این متغیر ممکن است توسط ابزارهایی نظیر run0 برای نمایش اطلاعات نشست تنظیم شود.
مرورگر وب دلخواه شما. اگر این متغیر تنظیم شده باشد، فیش به جای مرورگر پیش‌فرض سیستم از مرورگر مشخص‌شده برای نمایش مستندات فیش استفاده خواهد کرد.

فیش همچنین اطلاعات تکمیلی را از طریق مقادیر برخی متغیرهای محیطی فراهم می‌کند. بیشتر این متغیرها فقط‌خواندنی هستند و مقدار آن‌ها را نمی‌توان با set تغییر داد.

_
نام دستوری که در حال حاضر در حال اجرا است (البته این متغیر منسوخ شده و استفاده از status current-command ترجیح داده می‌شود).
فهرستی از آرگومان‌های ارسالی به پوسته یا تابع. متغیر argv تنها هنگام فراخوانی درون تابع تعریف شده است، یا اگر فیش همراه با فهرستی از آرگومان‌ها اجرا شده باشد، مانند fish myscript.fish foo bar. این متغیر قابل تغییر است.
دستور argparse <> این متغیر را روی فهرستی از گزینه‌های با موفقیت تجزیه‌شده، از جمله آرگومان‌های گزینه‌ها، تنظیم می‌کند. این متغیر قابل تغییر است.
مدت زمان اجرای آخرین دستور بر حسب میلی‌ثانیه.
اندازه فعلی ترمینال بر حسب ارتفاع و عرض. این مقادیر تنها زمانی توسط فیش استفاده می‌شوند که سیستم‌عامل اندازه ترمینال را گزارش نکند. در این حالت هر دو متغیر باید تنظیم شوند، در غیر این صورت مقدار پیش‌فرض 80x24 استفاده خواهد شد. با تغییر اندازه پنجره، این متغیرها به‌روزرسانی می‌شوند.
سیگنالی که آخرین کار پیش‌زمینه را پایان داده است، یا 0 در صورتی که کار به صورت عادی خاتمه یافته باشد.
فهرستی از ورودی‌ها در حلقه حذف (kill ring) متن‌های بریده‌شده در فیش <#killring>.
میزان بایتی که فیش با دستور read <> یا در یک جایگزینی دستور پردازش خواهد کرد.
شناسه فرآیند (PID) پوسته.
یک متغیر فقط‌خواندنی؛ هنگامی که ترمینال به ترتیب از تم رنگی روشن یا تیره استفاده می‌کند روی light یا dark تنظیم می‌شود؛ چنانچه ترمینال رنگ‌های خود را گزارش نکند، روی unknown قرار می‌گیرد <#term-compat-query-background-color>. همانند status terminal <#status-terminal>، این متغیر تنها پس از نمایش نخستین اعلان خط فرمان تعاملی مقداردهی می‌شود. از این متغیر در یک گرداننده رویداد --on-variable برای به‌روزرسانی متغیرهای برجسته‌سازی نحو <#syntax-highlighting> هر زمان که تم رنگی ترمینال دگرگون شود استفاده می‌گردد. برای نحوه تعیین گونه‌های light و dark در تم خود به اینجا مراجعه کنید <#fish-config-theme-files>.
فهرستی شامل آخرین دستوراتی که وارد شده‌اند.
دایرکتوری خانگی کاربر. این متغیر قابل تغییر است.
نام میزبان (hostname) سیستم.
جداکننده فیلد داخلی که برای تفکیک کلمات با دستور توکار read <> استفاده می‌شود. قرار دادن آن روی رشته خالی، تفکیک خطوط در جایگزینی دستور را نیز غیرفعال می‌سازد. این متغیر قابل تغییر است.
شناسه فرآیند (PID) آخرین فرآیند پس‌زمینه.
دایرکتوری کاری جاری.
فهرستی از وضعیت‌های خروج تمامی فرآیندهایی که آخرین پایپ اجراشده را تشکیل داده‌اند. وضعیت خروج را ببینید.
میزان سطح تودرتویی پوسته‌ها. فیش این مقدار را در پوسته‌های تعاملی افزایش می‌دهد، در غیر این صورت صرفاً آن را منتقل می‌کند.
وضعیت خروج آخرین کار پیش‌زمینه‌ای که پایان یافته است. اگر کار از طریق یک سیگنال متوقف شده باشد، وضعیت خروج برابر با ۱۲۸ به علاوه شماره سیگنال خواهد بود.
شمارنده «نسل» متغیر $status. این مقدار تنها زمانی افزایش می‌یابد که دستور قبلی یک وضعیت صریح تولید کرده باشد (برای مثال، کارهای پس‌زمینه این مقدار را افزایش نمی‌دهند).
نام کاربری جاری. این متغیر قابل تغییر است.
شناسه کاربری مؤثر جاری، که توسط فیش در هنگام راه‌اندازی تنظیم می‌شود. این متغیر قابل تغییر است.
نسخه فیش در حال اجرا (برای سازگاری با گذشته به صورت FISH_VERSION نیز در دسترس است).

به عنوان یک قرارداد، معمولاً برای متغیرهای صادرشده از حروف بزرگ و برای متغیرهای صادرنشده از حروف کوچک استفاده می‌شود (CMD_DURATION به دلایل تاریخی یک استثنا است). این قاعده توسط فیش تحمیل نمی‌شود، اما تمایز گذاشتن میان متغیرهای صادرشده و صادرنشده از طریق حروف‌بندی یک شیوه کدنویسی پسندیده است.

فیش همچنین از برخی متغیرها به صورت داخلی استفاده می‌کند که نام آن‌ها معمولاً با __fish آغاز می‌شود. این متغیرها داخلی هستند و معمولاً نباید مستقیماً تغییر داده شوند.

هر گاه فرآیندی به پایان می‌رسد، یک وضعیت خروج (exit status) به برنامه‌ای که آن را اجرا کرده (معمولاً پوسته) بازگردانده می‌شود. این وضعیت خروج یک عدد صحیح است که به برنامه فراخواننده می‌گوید اجرای دستور چگونه پیش رفته است. به طور کلی، وضعیت خروج صفر یعنی دستور بدون مشکل اجرا شده است، اما وضعیت خروج غیرصفر به معنای بروز نوعی خطا یا مشکل است.

فیش وضعیت خروج آخرین فرآیند از آخرین کاری را که خاتمه یافته است در متغیر status ذخیره می‌کند.

اگر فیش هنگام اجرای یک دستور با مشکلی روبرو شود، متغیر وضعیت ممکن است روی مقداری خاص تنظیم گردد:

  • 0 عموماً وضعیت خروج دستوراتی است که عملیات درخواستی را با موفقیت انجام داده‌اند.
  • 1 عموماً وضعیت خروج دستوراتی است که در اجرای عملیات درخواستی شکست خورده‌اند.
  • 121 عموماً وضعیت خروج دستوراتی است که آرگومان‌های نامعتبر به آن‌ها داده شده است.
  • 123 یعنی دستور اجرا نشد زیرا نام دستور حاوی نویسه‌های نامعتبر بود.
  • 124 یعنی دستور اجرا نشد زیرا هیچ‌یک از نویسه‌های عام در دستور به نتیجه‌ای منطبق نشدند.
  • 125 یعنی با اینکه فایلی اجرایی با نام مشخص‌شده یافت شد، سیستم‌عامل نتوانست دستور را اجرا کند.
  • 126 یعنی با اینکه فایلی با نام مشخص‌شده یافت شد، اما قابل اجرا نبود.
  • 127 یعنی هیچ تابع، دستور توکار یا دستور خارجی با این نام یافت نشد.

اگر فرآیندی با دریافت یک سیگنال پایان یابد، وضعیت خروج برابر با ۱۲۸ به علاوه شماره آن سیگنال خواهد بود.

وضعیت را می‌توان با کلیدواژه not <> (یا !) نفی کرد که در شرط‌ها بسیار کاربردی است. این عمل وضعیت 0 را به 1 و هر وضعیت غیرصفری را به 0 تبدیل می‌کند.

همچنین متغیر $pipestatus وجود دارد که فهرستی از تمامی مقادیر status فرآیندهای درون یک پایپ است. یک تفاوت این است که not <> بر روی $status اعمال می‌شود، اما روی $pipestatus اثر ندارد زیرا باعث از دست رفتن اطلاعات می‌گردد.

برای نمونه:

not cat file | grep -q fish
echo status is: $status pipestatus is $pipestatus

در اینجا $status نمایانگر وضعیت دستور grep است که در صورت یافتن مورد تطبیق 0 برمی‌گرداند، و با not نفی می‌شود (بنابراین در صورت یافتن 1 و در غیر این صورت 0 خواهد بود). متغیر $pipestatus وضعیت‌های دستور cat (که مثلاً در صورت نیافتن فایل مقداری غیرصفر برمی‌گرداند) و grep را بدون عمل نفی نشان می‌دهد.

بنابراین اگر هر دو دستور cat و grep موفق شوند، $status به دلیل وجود not برابر با 1 خواهد بود، در حالی که $pipestatus برابر با 0 و 0 خواهد شد.

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

برای مثال اگر خط لوله‌ای به این شکل داشته باشید:

cat file1 file2 | head -n 50

این دستور به cat می‌گوید دو فایل «file1» و «file2» را پشت سر هم چاپ کند، و دستور head تنها ۵۰ خط اول را نمایش می‌دهد. در این وضعیت ممکن است مکرراً چنین وضعیتی را مشاهده کنید:

> cat file1 file2 | head -n 50
# 50 lines of output
> echo $pipestatus
141 0

در اینجا مقدار «141» نشان می‌دهد که cat با سیگنال شماره ۱۳ (128 + 13 == 141) یعنی سیگنال SIGPIPE کشته شده است. همچنین می‌توانید از fish_kill_signal برای دیدن شماره سیگنال استفاده کنید. دلیل این رخداد این است که دستور هنوز در حال کار بود و سپس head لوله را بست؛ در نتیجه cat سیگنالی دریافت کرد که آن را نادیده نگرفت و به این ترتیب پایان یافت.

اینکه آیا cat در اینجا با یک SIGPIPE مواجه می‌شود یا خیر به طول فایل و حجم داده‌ای که در یک لحظه می‌نویسد بستگی دارد، بنابراین ممکن است بسته به پیاده‌سازی، متغیر pipestatus را به صورت «0 0» مشاهده کنید. این یک مسئله عمومی در یونیکس است و مختص فیش نیست. برخی از پوسته‌ها از قابلیتی به نام «pipefail» برخوردارند که در صورت شکست هر یک از فرآیندهای لوله کل آن را ناموفق اعلام می‌کنند، و این موضوع چالشی بزرگ برای آن ویژگی محسوب می‌شود.

تنظیمات محلی‌سازی (locale) یک برنامه، مجموعه تنظیمات زبانی و منطقه‌ای آن است. در یونیکس، این موارد از چندین دسته‌بندی تشکیل شده‌اند. دسته‌بندی‌های مورد استفاده در فیش عبارتند از:

این متغیر محیطی متداول برای تعیین زبان و محیط محلی است. کاربر می‌تواند این متغیر را برای بیان زبانی که به آن صحبت می‌کند، منطقه خود، و کدگذاری نویسه‌ها تنظیم نماید. بخش کدگذاری نادیده گرفته می‌شود؛ فیش همیشه UTF-8 را در نظر می‌گیرد. مقادیر واقعی به پلتفرم کاربر وابسته‌اند، به جز مقادیر خاصی نظیر C یا POSIX.

مقدار LANG برای هر دسته‌بندی استفاده می‌شود مگر آنکه متغیر اختصاصی آن دسته‌بندی یا متغیر LC_ALL تنظیم شده باشد. بنابراین معمولاً تنها کافی است LANG را تنظیم کنید.

مقادیر نمونه شامل en_US.UTF-8 برای انگلیسی آمریکایی یا de_AT.UTF-8 برای آلمانی اتریشی است. سیستم‌عامل شما ممکن است دستوری به نام locale داشته باشد که با اجرای locale -a می‌توانید فهرستی از محیط‌های محلی تعریف‌شده را مشاهده کنید.

با این متغیر همانند LC_MESSAGES رفتار می‌شود، با این تفاوت که می‌تواند چندین مقدار را نگهداری کند، که امکان تعیین فهرستی اولویت‌بندی‌شده از زبان‌ها را برای ترجمه فراهم می‌سازد. این یک متغیر مسیر (PATH variable) است، مشابه سیستم GNU gettext https://www.gnu.org/software/gettext/manual/html_node/The-LANGUAGE-variable.html.

شناسه‌های زبانی بدون منطقه مشخص (مانند zh) باعث می‌شوند تمامی گونه‌های موجود از آن زبان به ترتیبی اختیاری امتحان شوند. در این مثال، ممکن است ابتدا پیام‌ها در کاتالوگ zh_CN و سپس در zh_TW جستجو شوند، یا برعکس. این رفتار با GNU gettext که از گونه «پیش‌فرض» زبان استفاده می‌کند تفاوت دارد. اگر گونه خاصی را ترجیح می‌دهید، آن را جلوتر در فهرست مشخص کنید، برای مثال zh_TW:zh در صورتی که زبان ترجیحی شما zh_TW باشد و هر گونه دیگری از zh را به انگلیسی پیش‌فرض ترجیح دهید. اگر zh_TW تنها گونه‌ای از zh است که می‌خواهید، مشخص کردن zh_TW در متغیر LANGUAGE موجب می‌شود پیام‌هایی که در zh_TW در دسترس نیستند به زبان انگلیسی نمایش یابند.

دستور توکار _ (زیرخط) را نیز ببینید <>.

متغیر LANG و تمامی متغیرهای دیگر LC_* را بازنویسی می‌کند. لطفاً از LC_ALL صرفاً به عنوان یک بازنویسی موقت استفاده کنید.
زبانی را که پیام‌ها به آن نمایش داده می‌شوند مشخص می‌کند؛ دستور توکار _ (زیرخط) را ببینید <>.
تنظیمات محلی را برای قالب‌بندی اعداد مشخص می‌کند <>.
نحوه نمایش تاریخ و زمان را مشخص می‌کند. در دستور توکار history استفاده می‌شود <#history-show-time>.

پوسته فیش شامل تعدادی دستور است که مستقیماً درون خود پوسته پیاده‌سازی شده‌اند. ما این‌ها را «دستورات توکار» (builtins) می‌نامیم. این موارد شامل موارد زیر است:

  • دستورات توکاری که وضعیت پوسته را دستکاری می‌کنند - مانند cd <> که دایرکتوری را تغییر می‌دهد، و set <> که متغیرها را مقداردهی می‌کند.
  • دستورات توکار برای کار با داده‌ها، مانند string <> برای رشته‌ها و math <> برای اعداد، count <> برای شمارش خطوط یا آرگومان‌ها، و path <> برای مدیریت مسیرها.
  • دستور status <> برای جویا شدن از وضعیت پوسته.
  • دستورات printf <> و echo <> برای تولید خروجی.
  • دستور test <> برای بررسی شرط‌ها.
  • دستور argparse <> برای تجزیه آرگومان‌های توابع.
  • دستور source <> برای خواندن یک اسکریپت در پوسته جاری (تا تغییرات متغیرها باقی بمانند) و eval <> برای اجرای یک رشته در قالب اسکریپت.
  • دستور random <> برای دریافت اعداد تصادفی یا انتخاب یک عنصر تصادفی از یک فهرست.
  • دستور read <> برای خواندن ورودی از پایپ یا ترمینال.

برای مشاهده فهرست تمامی دستورات توکار، از builtin -n استفاده کنید.

برای دیدن فهرستی از تمامی دستورات توکار، توابع و دستورات همراه با فیش، فهرست دستورات را ببینید <>. مستندات آن‌ها همچنین با استفاده از سوییچ --help در دسترس است.

هنگامی که به فیش گفته می‌شود برنامه‌ای را اجرا کند، چندین مرحله را برای یافتن آن طی می‌کند.

اگر نام شامل یک کاراکتر / باشد، فیش تلاش می‌کند فایل مورد نظر را با شروع از دایرکتوری جاری اجرا کند.

اگر شامل / نباشد، می‌تواند یک تابع، دستور توکار یا یک دستور خارجی باشد؛ بنابراین فیش مراحل جستجوی کامل را به این ترتیب طی می‌کند:

1.
تلاش می‌کند آن را به عنوان یک تابع حل‌وفصل کند:
  • اگر تابع از قبل شناخته شده باشد، از همان استفاده می‌کند.
  • اگر فایلی با همان نام و پسوند «.fish» در fish_function_path موجود باشد، آن را بارگذاری می‌کند (اگر بیش از یک فایل وجود داشته باشد، فقط اولی استفاده می‌شود).
  • اگر تابع اکنون تعریف شده باشد، از آن استفاده می‌کند.
2.
تلاش می‌کند آن را به عنوان یک دستور توکار حل‌وفصل کند.
3.
تلاش می‌کند فایلی اجرایی را در PATH بیابد:
  • اگر فایلی پیدا کند، به هسته (کرنل) دستور می‌دهد آن را اجرا کند.
  • اگر هسته بداند چگونه فایل را اجرا کند (مثلاً از طریق خط شه‌بنگ #! مانند #!/bin/sh یا #!/usr/bin/python)، آن را اجرا می‌کند.
  • اگر هسته گزارش دهد که به دلیل نبود مفسر نتوانسته آن را اجرا کند، و فایل از یک بررسی اولیه موفق بیرون آید، فیش به /bin/sh می‌گوید آن را اجرا کند.

اگر هیچ‌یک از این روش‌ها کارساز نباشد، فیش تابع fish_command_not_found <> را اجرا کرده و متغیر status را روی 127 قرار می‌دهد.

می‌توانید از دستور type <> برای دیدن نحوه حل‌وفصل یک دستور توسط فیش استفاده کنید:

> type --short --all echo
echo is a builtin
echo is /usr/bin/echo

گاهی می‌خواهید از کاربر ورودی بگیرید، مثلاً برای تأیید یک عمل. این کار با دستور توکار read <> انجام می‌شود.

بیایید مثالی مطرح کنیم. این تابع فایل‌های درون تمام دایرکتوری‌هایی را که به عنوان آرگومان دریافت کرده با الگوهای عام تطبیق می‌دهد، و اگر بیش از ۵ مورد باشند، از کاربر می‌پرسد که آیا مایل به دیدن آن‌ها هست یا خیر؛ البته تنها در صورتی که به یک ترمینال متصل باشد:

function show_files
    # This will glob on all arguments. Any non-directories will be ignored.
    set -l files $argv/*
    # If there are more than 5 files
    if test (count $files) -gt 5
        # and both stdin (for reading input)
        # and stdout (for writing the prompt)
        # are terminals
        and isatty stdin
        and isatty stdout
        # Keep asking until we get a valid response
        while read --nchars 1 -l response --prompt-str="Are you sure? (y/n)"
              or return 1 # if the read was aborted with ctrl-c/ctrl-d
            switch $response
                case y Y
                    echo Okay
                    # We break out of the while and go on with the function
                    break
                case n N
                    # We return from the function without printing
                    echo Not showing
                    return 1
                case '*'
                    # We go through the while loop and ask again
                    echo Not valid input
                    continue
            end
        end
    end
    # And now we print the files
    printf '%s\n' $files
end

اگر این تابع را به صورت show_files / اجرا کنید، به احتمال زیاد مرتباً از شما سؤال می‌پرسد تا زمانی که Y/y یا N/n را فشار دهید. اگر آن را به صورت show_files / | cat اجرا کنید، بدون پرسش فایل‌ها را چاپ می‌کند. و اگر آن را به صورت show_files . اجرا کنید، ممکن است بدون پرسش محتوا را چاپ کند زیرا تعداد فایل‌ها کمتر از پنج است.

نام‌هایی که به متغیرها و توابع داده می‌شوند (شناسه‌ها یا identifiers) باید از قواعد معینی پیروی کنند:

  • نام یک متغیر نمی‌تواند خالی باشد. تنها می‌تواند شامل حروف، ارقام و زیرخط باشد. می‌تواند با هر یک از این نویسه‌ها آغاز شده یا پایان یابد.
  • نام یک تابع نمی‌تواند خالی باشد. نباید با خط تیره («-») شروع شود و نباید شامل اسلش («/») باشد. تمامی نویسه‌های دیگر، از جمله فاصله، معتبر هستند. همچنین نام تابع نمی‌تواند هم‌نام با یک کلیدواژه رزروشده یا یک دستور توکار حیاتی مانند if یا set باشد.
  • نام حالت نگاشت کلید (مانند bind -m abc ...) باید یک نام متغیر معتبر باشد.

سایر موارد محدودیت‌های دیگری دارند. برای نمونه آنچه برای نام فایل‌ها مجاز است به سیستم شما بستگی دارد، اما حداقل نمی‌توانند حاوی «/» (چون جداکننده مسیر است) یا بایت تهی (NULL) باشند (چون یونیکس رشته‌ها را با آن خاتمه می‌دهد).

هنگام راه‌اندازی فیش، فایل‌های پیکربندی آن خوانده و اجرا می‌شوند. محل این فایل‌ها به پیکربندی ساخت و متغیرهای محیطی وابسته است.

فایل اصلی ~/.config/fish/config.fish است (یا به طور دقیق‌تر $XDG_CONFIG_HOME/fish/config.fish).

فایل‌های پیکربندی به این ترتیب اجرا می‌شوند:

•
قطعه‌کدهای پیکربندی (با نام *.fish) در این دایرکتوری‌ها:
  • $__fish_config_dir/conf.d (به صورت پیش‌فرض، ~/.config/fish/conf.d/)
  • $__fish_sysconf_dir/conf.d (به صورت پیش‌فرض، /etc/fish/conf.d/)
  • دایرکتوری‌هایی برای نرم‌افزارهای دیگر جهت عرضه قطعه‌کدهای پیکربندی خود:
  • دایرکتوری‌های زیرمجموعه $__fish_user_data_dir (معمولاً ~/.local/share/fish، کنترل‌شده با متغیر محیطی XDG_DATA_HOME)
  • دایرکتوری fish/vendor_conf.d درون دایرکتوری‌های فهرست‌شده در $XDG_DATA_DIRS (پیش‌فرض /usr/share/fish/vendor_conf.d و /usr/local/share/fish/vendor_conf.d)

این دایرکتوری‌ها از طریق $__fish_vendor_confdirs نیز در دسترس هستند. توجه داشته باشید که تغییر این متغیر در یک پوسته در حال اجرا اثری نخواهد داشت، زیرا تا آن لحظه دایرکتوری‌ها خوانده شده‌اند.

اگر چندین فایل هم‌نام در این دایرکتوری‌ها وجود داشته باشد، تنها نخستین مورد اجرا می‌شود. آن‌ها به ترتیب نام فایل و با مرتب‌سازی طبیعی (مانند الگوهای عام) اجرا می‌شوند (یعنی «01» قبل از «2» مرتب می‌شود).

  • فایل‌های پیکربندی سراسری سیستم، که مدیران سیستم می‌توانند مقداردهی اولیه برای تمامی کاربران را در آن بگنجانند - مشابه /etc/profile در پوسته‌های سبک پازیکس - در $__fish_sysconf_dir (معمولاً /etc/fish/config.fish).
  • پیکربندی کاربر، معمولاً در ~/.config/fish/config.fish (کنترل‌شده با متغیر محیطی XDG_CONFIG_HOME، و قابل دسترسی با نام $__fish_config_dir).

فایل ~/.config/fish/config.fish پس از قطعه‌کدها بارگذاری می‌شود. این ترتیب به شما اجازه می‌دهد قطعه‌کدها را کپی کرده و برخی رفتارهای آن‌ها را بازنویسی کنید.

این فایل‌ها هنگام شروع به کار هر پوسته اجرا می‌شوند. اگر می‌خواهید دستوری را تنها هنگام راه‌اندازی یک پوسته تعاملی اجرا کنید، از وضعیت خروج دستور status --is-interactive برای تشخیص تعاملی بودن پوسته بهره ببرید. اگر می‌خواهید دستوری را فقط در پوسته ورود (login shell) اجرا کنید، از status --is-login استفاده نمایید. این کار سرعت راه‌اندازی پوسته‌های غیرتعاملی یا غیرورودی را افزایش می‌دهد.

اگر در حال توسعه برنامه‌ای دیگر هستید، ممکن است بخواهید پیکربندی برای تمامی کاربران فیش روی سیستم بیفزایید. این کار توصیه نمی‌شود؛ اگر با دقت نوشته نشود ممکن است اثرات جانبی داشته باشد یا راه‌اندازی پوسته را کند کند. علاوه بر این، کاربران سایر پوسته‌ها از پیکربندی مختص فیش بهره‌مند نخواهند شد. با این حال اگر ضروری باشد، می‌توانید آن‌ها را در دایرکتوری پیکربندی «تأمین‌کننده» (vendor) نصب کنید. از آنجا که این مسیر در سیستم‌های مختلف متغیر است، باید از pkg-config برای یافتن آن استفاده کرد: pkg-config --variable confdir fish.

برای یکپارچه‌سازی با سیستم، فیش همچنین فایلی به نام __fish_build_paths.fish ارائه می‌دهد. این فایل می‌تواند هنگام ساخت شخصی‌سازی شود، مثلاً در صورتی که سیستم شما به مسیرهای خاصی نیاز داشته باشد.

فلگ‌های ویژگی روشی است که فیش برای اعمال تغییراتی که ممکن است اسکریپت‌ها را بشکنند استفاده می‌کند. تغییرات شکننده ابتدا به صورت اختیاری (opt-in) معرفی می‌شوند، در چند انتشار بعد به صورت پیش‌فرض فعال اما قابل غیرفعال‌سازی (opt-out) درمی‌آیند، و در نهایت رفتار قدیمی به کلی حذف می‌شود.

می‌توانید فهرست ویژگی‌های فعلی را با status features مشاهده کنید:

> status features
stderr-nocaret          on  3.0 ^ no longer redirects stderr
qmark-noglob            on  3.0 ? no longer globs
regex-easyesc           on  3.1 string replace -r needs fewer \\'s
ampersand-nobg-in-token on  3.4 & only backgrounds if followed by a separating character
remove-percent-self     off 4.0 %self is no longer expanded (use $fish_pid)
test-require-arg        off 4.0 builtin test requires an argument
mark-prompt             on  4.0 write OSC 133 prompt markers to the terminal
ignore-terminfo         on  4.1 do not look up $TERM in terminfo database
query-term              on  4.1 query the TTY to enable extra functionality
omit-term-workarounds   off 4.3 skip workarounds for incompatible terminals

مفهوم این ویژگی‌ها به شرح زیر است:

  • فلگ stderr-nocaret در فیش ۳.۰ معرفی شد و از فیش ۳.۵ به بعد نمی‌توان آن را خاموش کرد. هنوز می‌توان آن را برای سازگاری بررسی کرد، اما مقدار no-stderr-nocaret نادیده گرفته می‌شود. این فلگ علامت ^ را به یک کاراکتر معمولی به جای تغییرمسیر stderr تبدیل کرد. به جای آن از 2> استفاده کنید.
  • فلگ qmark-noglob نیز در فیش ۳.۰ معرفی شد (و در ۴.۰ پیش‌فرض شد). این فلگ علامت ? را به یک نویسه معمولی به جای الگوی عام تک‌کاراکتری تبدیل می‌کند. به جای آن از * استفاده کنید (که چندین کاراکتر را مطابقت می‌دهد) یا از راه‌های دیگر تطبیق فایل مانند find بهره ببرید.
  • فلگ regex-easyesc در نسخه ۳.۱ معرفی شد (و در ۳.۵ پیش‌فرض شد). این فلگ باعث می‌شود عبارت جایگزینی در string replace -r به یک دور گریزدهی کمتر نیاز داشته باشد. پیش از این، برای گریز دادن بک‌اسلش باید از string replace -ra '([ab])' '\\\\\\\\$1' استفاده می‌کردید؛ پس از آن عبارت '\\\\$1' کافی است. اگر در جایی از این دستور استفاده کرده‌اید، فراخوانی‌های string replace خود را بررسی کنید.
  • فلگ ampersand-nobg-in-token در فیش ۳.۴ معرفی شد (و در ۳.۵ پیش‌فرض شد). این ویژگی موجب می‌شود که نویسه & در میان یک توکن دیگر به عنوان عملگر پس‌زمینه تفسیر نشود، تا کار با URLها آسان‌تر گردد. بعد از & یا فاصله بگذارید یا نقطه‌ویرگول. به هر حال این فرمت‌بندی پیشنهادی است و ابزار fish_indent قبلاً آن را برای شما انجام داده است.
  • فلگ remove-percent-self بسط ویژه %self را خاموش می‌کند. در نسخه ۴.۰ معرفی شد. برای به دست آوردن pid فیش، می‌توانید از متغیر fish_pid استفاده کنید.
  • فلگ test-require-arg حالت تک‌آرگومانی دستور توکار test <> را حذف می‌کند (test "string"). در ۴.۰ معرفی شد. برای بررسی خالی نبودن یک رشته، از test -n "string" استفاده کنید. در صورت غیرفعال بودن، هر فراخوانی به test که تغییر رفتار داشته باشد پیامی اشکال‌زدایی <#debugging-fish> در دسته‌بندی «deprecated-test» می‌فرستد، بنابراین راه‌اندازی فیش با fish --debug=deprecated-test می‌تواند برای یافتن فراخوانی‌های ناسازگار استفاده شود.
  • فلگ mark-prompt باعث می‌شود فیش آغاز و پایان اعلان‌های پوسته و خروجی دستورات را با کدهای OSC 133 به ترمینال گزارش کند.
  • فلگ ignore-terminfo در فیش ۴.۱ معرفی شد و از فیش ۴.۵ به بعد غیرفعال نمی‌شود. این فلگ جستجوی متغیر $TERM در پایگاه‌داده terminfo را غیرفعال کرد.
  • فلگ query-term به فیش اجازه می‌دهد با نوشتن توالی‌های گریز و خواندن پاسخ ترمینال، ویژگی‌های آن را استعلام کند. این قابلیت ویژگی‌هایی نظیر اسکرول را فعال می‌سازد <#term-compat-cursor-position-report>. اگر از ترمینالی ناسازگار استفاده می‌کنید، فعلاً می‌توانید با اجرای دستور (یک‌باره) set -Ua fish_features no-query-term این مشکل را دور بزنید.
  • فلگ omit-term-workarounds مانع از تلاش فیش برای رفع ناسازگاری‌های ترمینال‌های ناسازگار می‌شود.

این تغییرات در ابتدا به صورت غیرفعال عرضه می‌شوند. می‌توان آن‌ها را بر اساس هر نشست فعال کرد:

> fish --features qmark-noglob,regex-easyesc

یا به صورت سراسری برای یک کاربر انتخاب نمود:

> set -U fish_features regex-easyesc qmark-noglob

ویژگی‌ها تنها در هنگام راه‌اندازی تنظیم می‌شوند، بنابراین این متغیر تنها در صورتی اثرگذار خواهد بود که جهانی (universal) یا صادرشده (exported) باشد.

همچنین می‌توانید شماره نسخه را به عنوان یک گروه به کار ببرید؛ برای مثال 3.0 معادل «stderr-nocaret» و «qmark-noglob» است. به جای نسخه، گروه ویژه all تمامی ویژگی‌ها را فعال می‌کند.

افزودن پیشوند no- به یک ویژگی، آن را خاموش می‌کند. برای مثال برای فعال‌سازی مجدد الگوی عام تک‌کاراکتری ?:

set -Ua fish_features no-qmark-noglob

هنگام تعریف یک تابع جدید در فیش، امکان تبدیل آن به یک گرداننده رویداد (event handler) وجود دارد؛ یعنی تابعی که هنگام وقوع رویدادی مشخص به طور خودکار اجرا شود. رویدادهایی که در حال حاضر می‌توانند یک گرداننده را تحریک کنند عبارتند از:

  • هنگام ارسال یک سیگنال
  • هنگامی که یک کار (job) خاتمه می‌یابد
  • هنگامی که مقدار یک متغیر به‌روزرسانی می‌شود
  • هنگامی که اعلان خط فرمان در شرف نمایش است

مثال:

برای مشخص کردن یک گرداننده سیگنال برای سیگنال WINCH، بنویسید:

function my_signal_handler --on-signal WINCH
    echo Got WINCH signal!
end

فیش از قبل رویدادهای نام‌گذاری‌شده زیر را برای سوییچ --on-event داراست:

  • رویداد fish_prompt هر زمان که یک اعلان خط فرمان جدید در شرف نمایش باشد ارسال می‌شود.
  • رویداد fish_preexec درست قبل از اجرای یک دستور تعاملی ارسال می‌شود. خط فرمان به عنوان اولین پارامتر به آن فرستاده می‌شود. اگر دستور خالی باشد ارسال نمی‌گردد.
  • رویداد fish_posterror درست پس از اجرای دستوری با خطای نحوی ارسال می‌شود. خط فرمان به عنوان نخستین پارامتر ارسال می‌شود.
  • رویداد fish_postexec بلافاصله پس از اجرای یک دستور تعاملی ارسال می‌شود. خط فرمان به عنوان پارامتر اول ارسال می‌گردد. اگر دستور خالی باشد ارسال نمی‌شود.
  • رویداد fish_exit درست پیش از خروج فیش ارسال می‌شود.
  • رویداد fish_cancel هنگامی که یک خط فرمان پاک می‌شود ارسال می‌گردد.
  • رویداد fish_focus_in زمانی که ترمینال فیش فوکوس دریافت می‌کند ارسال می‌شود.
  • رویداد fish_focus_out زمانی که ترمینال فیش فوکوس را از دست می‌دهد ارسال می‌شود.

رویدادها را می‌توان با دستور emit <> شلیک کرد و نیازی نیست از قبل تعریف شده باشند؛ تنها کافی است نام‌ها تطبیق داشته باشند. برای مثال:

function handler --on-event imdone
    echo generator is done $argv
end
function generator
    sleep 1
    # The "imdone" is the name of the event
    # the rest is the arguments to pass to the handler
    emit imdone with $argv
end

اگر چندین گرداننده برای یک رویداد وجود داشته باشد، همگی اجرا خواهند شد، اما ممکن است ترتیب اجرا میان نسخه‌های فیش تغییر کند؛ بنابراین نباید به ترتیب آن اتکا کنید.

لطفاً توجه داشته باشید که گرداننده‌های رویداد تنها زمانی فعال می‌شوند که تابع بارگذاری شده باشد؛ این یعنی باید با source <> یا اجرای مستقیم، تابع را بارگذاری کنید و به بارگذاری خودکار اتکا ننمایید. یک روش، قرار دادن آن در فایل پیکربندی است.

برای اطلاعات بیشتر درباره نحوه تعریف گرداننده‌های رویداد جدید، مستندات دستور function <> را ببینید.

پوسته فیش شامل امکانات پایه‌ای اشکال‌زدایی داخلی است که به شما امکان می‌دهد اجرای اسکریپت را در نقطه‌ای دلخواه متوقف کنید. هنگام وقوع این حالت، یک اعلان خط فرمان تعاملی به شما ارائه می‌شود که در آن می‌توانید هر دستور فیش را برای بازرسی یا تغییر وضعیت اجرا کنید (دستورات اشکال‌زدایی اختصاصی مجزایی وجود ندارد). برای نمونه، می‌توانید مقدار هر متغیر را با استفاده از printf <> و set <> بررسی کرده یا تغییر دهید. به عنوان نمونه‌ای دیگر، می‌توانید دستور status print-stack-trace <> را اجرا کنید تا ببینید چگونه به نقطه توقف (breakpoint) فعلی رسیده‌اید. برای از سرگیری اجرای عادی اسکریپت، دستور exit <> را تایپ کنید یا کلیدهای ترکیبی ctrl-d را بفشارید.

برای شروع یک نشست اشکال‌زدایی، دستور توکار breakpoint را در نقطه‌ای از تابع یا اسکریپت که می‌خواهید کنترل را به دست بگیرید درج کنید <>، سپس تابع یا اسکریپت را اجرا نمایید. همچنین رفتار پیش‌فرض سیگنال TRAP فراخوانی این دستور توکار است، به این معنی که یک اسکریپت در حال اجرا می‌تواند با ارسال سیگنال TRAP به طور فعال اشکال‌زدایی شود (kill -s TRAP <PID>). پشتیبانی محدودی برای تنظیم یا تغییر تعاملی نقاط توقف از این اعلان اشکال‌زدایی وجود دارد: می‌توان با استفاده از تابع funced نقاط توقف جدیدی در سایر توابع قرار داد (یا نقاط قدیمی را حذف کرد)، اما افزودن یا حذف نقطه توقف از تابع/اسکریپتی که در حال حاضر بارگذاری شده و در حال اجراست امکان‌پذیر نیست.

راه دیگر برای اشکال‌زدایی مشکلات اسکریپت‌ها، تنظیم متغیر fish_trace است؛ مانند fish_trace=1 fish_prompt برای مشاهده دستوراتی که فیش هنگام اجرای تابع fish_prompt <> اجرا می‌کند.

اگر به طور مشخص می‌خواهید مسائل مربوط به عملکرد و کارایی را اشکال‌زدایی کنید، fish را می‌توان با گزینه --profile /path/to/profile.log اجرا کرد تا اطلاعات پروفایل را در مسیر مشخص‌شده ذخیره کند. این گزارش پروفایل شامل تفکیک مدت زمانی است که هر گام در فرآیند اجرا طول کشیده است.

برای مثال:

> fish --profile /tmp/sleep.prof -ic 'sleep 3s'
> cat /tmp/sleep.prof
Time    Sum     Command
3003419 3003419 > sleep 3s

این دستور زمان لازم برای خود دستور را در ستون اول، زمان کل برای دستور و تمامی زیردستورات (مانند هر دستوری درون تابع یا جایگزینی‌های دستور) را در ستون دوم، و خود دستور را در ستون سوم، جداشده با تب، نشان می‌دهد.

زمان بر حسب میکروثانیه ارائه می‌شود.

برای دیدن کندترین دستورات در انتها، دستور sort -nk2 /path/to/logfile کاربردی است.

برای پروفایل زمان راه‌اندازی فیش، گزینه --profile-startup /path/to/logfile نیز وجود دارد.

برای اطلاعات بیشتر مستندات fish <> را ببینید.

توسعه‌دهندگان پوسته فیش (fish-shell developers)

توسعه‌دهندگان پوسته فیش (fish-shell developers)

September 7, 2026 4.9