Spec-Zone.ru › Fish 3.6

Язык команд fish

Этот документ — подробный обзор языка сценариев fish.

Для интерактивных функций см. Интерактивное использование.

Обзор синтаксиса

Оболочки, такие как 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: Отображение содержимого файлов

Команды и аргументы разделяются пробелом ' '. Каждая команда заканчивается либо новой строкой (нажатием клавиши ввода), либо точкой с запятой ;. Несколько команд могут быть записаны в одной строке, разделяя их точками с запятой.

Переключатель — это очень распространенный специальный тип аргумента. Переключатели почти всегда начинаются с одной или нескольких тире - и изменяют способ работы команды. Например, команда ls обычно выводит имена всех файлов и каталогов в текущем рабочем каталоге. Используя переключатель -l, поведение ls изменяется так, что он не только отображает имя файла, но также размер, разрешения, владельца и время последнего изменения каждого файла.

Переключатели различаются между командами и обычно документируются в справке по команде. Однако существуют некоторые переключатели, которые являются общими для большинства команд. Например, --help обычно отображает текст справки, --version обычно отображает версию команды, а -i часто включает интерактивное запросы перед выполнением действия. Попробуйте man your-command-here для получения информации о переключателях вашей команды.

Таким образом, основная идея fish такая же, как и в других оболочках Unix: она получает командную строку, выполняет расширения, а результат затем выполняется как команда.

Терминология

Здесь мы определяем некоторые термины, используемые на этой странице и во всей остальной документации fish:

  • Аргумент: Параметр, передаваемый команде. В echo foo, «foo» — аргумент.
  • Встроенная команда: Команда, реализованная в оболочке. Встроенные команды так тесно связаны с работой оболочки, что их невозможно реализовать как внешние команды. В echo foo, «echo» — встроенная команда.
  • Команда: Программа, которую может запустить оболочка, или, более конкретно, внешняя программа, которую оболочка запускает в другом процессе. Внешние команды предоставляются вашей системой как исполняемые файлы. В echo foo «echo» — встроенная команда, в command echo foo «echo» — внешняя команда, предоставляемая файлом, таким как /bin/echo.
  • Функция: Блок команд, который можно вызывать, как если бы это была одна команда. С помощью функций можно объединить несколько простых команд в одну более сложную команду.
  • Задача: Запущенная цепочка команд или команда.
  • Цепочка команд: Набор команд, связанных вместе таким образом, что вывод одной команды является вводом следующей команды. echo foo | grep foo — это цепочка команд.
  • Перенаправление: Операция, изменяющая один из потоков ввода или вывода, связанных с задачей.
  • Переключатель или Опция: Специальный вид аргумента, изменяющий поведение команды. Переключатель почти всегда начинается с одного или двух тире. В echo -n foo «-n» — опция.

Кавычки

Иногда такие функции, как расширение параметров и экранирование символов, мешают. В таких случаях вы можете использовать кавычки, одинарные (') или двойные ("). В одинарных кавычках fish не выполняет никаких расширений. В двойных кавычках fish выполняет только расширение переменных. Никакие другие виды расширений (включая расширение фигурных скобок или расширение параметров) не выполняются, и управляющие последовательности (например, \n) игнорируются. В кавычках пробелы не используются для разделения аргументов, что позволяет аргументам в кавычках содержать пробелы.

Единственными значимыми управляющими последовательностями в одинарных кавычках являются \', которая экранирует одинарную кавычку, и \\, которая экранирует символ обратной косой черты. Единственными значимыми экранированиями в двойных кавычках являются \", которая экранирует двойную кавычку, \$, которая экранирует символ доллара, \ , за которым следует новая строка, что удаляет обратную косую черту и новую строку, и \\, которая экранирует символ обратной косой черты.

Одинарные кавычки не имеют специального значения внутри двойных кавычек и наоборот.

Пример:

rm "cumbersome filename.txt"

удаляет файл cumbersome filename.txt, в то время как

rm cumbersome filename.txt

удаляет два файла, cumbersome и filename.txt.

Другой пример:

grep 'enabled)$' foo.txt

ищет строки, заканчивающиеся на enabled) в foo.txt ($ специальный для grep: он соответствует концу строки).

END_OF_DOCUMENT_MARKER

Символы экранирования

Некоторые символы нельзя вводить непосредственно в командной строке. Для этих символов предусмотрены так называемые последовательности экранирования. Это:

  • \a представляет символ оповещения.
  • \e представляет символ экранирования.
  • \f представляет символ перевода страницы.
  • \n представляет символ новой строки.
  • \r представляет символ возврата каретки.
  • \t представляет символ табуляции.
  • \v представляет символ вертикальной табуляции.
  • \xHH или \XHH, где HH — шестнадцатеричное число, представляет байт данных со значением. Например, \x9 — это символ табуляции. Если вы используете многобайтовую кодировку, это можно использовать для ввода недопустимых строк. Обычно fish запускается с кодировкой ASCII или UTF-8, поэтому все до \X7f — это символ ASCII.
  • \ooo, где ooo — восьмеричное число, представляет символ ASCII со значением. Например, \011 — это символ табуляции. Максимально допустимое значение — \177.
  • \uXXXX, где XXXX — шестнадцатеричное число, представляет 16-битный символ Unicode со значением. Например, \u9 — это символ табуляции.
  • \UXXXXXXXX, где XXXXXXXX — шестнадцатеричное число, представляет 32-битный символ Unicode со значением. Например, \U9 — это символ табуляции. Максимально допустимое значение — U10FFFF.
  • \cX, где X — буква алфавита, представляет управляющую последовательность, генерируемую нажатием клавиши управления и указанной буквы. Например, \ci — это символ табуляции.

Некоторые символы имеют специальное значение для оболочки. Например, апостроф ' отключает расширение (см. Кавычки). Чтобы оболочка обрабатывала эти символы буквально, экранируйте их обратной косой чертой. Например, команда:

echo \'hello world\'

выводит 'hello world' (включая апострофы), а команда:

echo 'hello world'

выводит hello world (без апострофов). В первом случае оболочка обрабатывает апострофы как буквальные ' символы, а во втором — как специальные модификаторы расширения.

Специальные символы и их последовательности экранирования:

  • \  (обратная косая черта пробел) экранирует пробел. Это предотвращает разделение аргументов на пробелы.
  • \$ экранирует символ доллара.
  • \\ экранирует символ обратной косой черты.
  • \* экранирует символ звездочки.
  • \? экранирует символ вопроса (это не обязательно, если включен флаг qmark-noglob флага).
  • \~ экранирует символ тильды.
  • \# экранирует символ решетки.
  • \( экранирует символ открывающей скобки.
  • \) экранирует символ закрывающей скобки.
  • \{ экранирует символ открывающей фигурной скобки.
  • \} экранирует символ закрывающей фигурной скобки.
  • \[ экранирует символ открывающей квадратной скобки.
  • \] экранирует символ закрывающей квадратной скобки.
  • \< экранирует символ меньше.
  • \> экранирует символ больше.
  • \& экранирует символ амперсанда.
  • \| экранирует символ вертикальной черты.
  • \; экранирует символ точки с запятой.
  • \" экранирует символ кавычки.
  • \' экранирует символ апострофа.

В качестве особого случая \ непосредственно после символа новой строки является «продолжением» и указывает fish игнорировать перевод строки и возобновить ввод в начале следующей строки (без ввода пробелов или завершения маркера).

Перенаправление ввода/вывода

Большинство программ используют три потока ввода/вывода (I/O):

  • Стандартный ввод (stdin) для чтения. По умолчанию считывает данные с клавиатуры.
  • Стандартный вывод (stdout) для вывода. По умолчанию выводит на экран.
  • Стандартная ошибка (stderr) для вывода ошибок и предупреждений. По умолчанию выводит на экран.

Каждый поток имеет номер, называемый дескриптором файла (FD): 0 для stdin, 1 для stdout и 2 для stderr.

Назначение потока можно изменить, используя перенаправление. Например, echo hello > output.txt, перенаправляет стандартный вывод команды echo в текстовый файл.

  • Для чтения стандартного ввода из файла используйте <SOURCE_FILE.
  • Для записи стандартного вывода в файл используйте >DESTINATION.
  • Для записи стандартной ошибки в файл используйте 2>DESTINATION. [1]
  • Для добавления стандартного вывода в файл используйте >>DESTINATION_FILE.
  • Для добавления стандартной ошибки в файл используйте 2>>DESTINATION_FILE.
  • Чтобы не перезаписывать существующий файл, используйте >?DESTINATION или 2>?DESTINATION. Это известно как перенаправление «noclobber».

DESTINATION может быть одним из следующих:

  • Имя файла для записи вывода. Часто >/dev/null для отключения вывода, записывая его в специальный «утилитарный» файл.
  • Амперсанд (&) за которым следует номер другого дескриптора файла, например, &2 для стандартной ошибки. Вывод будет записан в дескриптор назначения.
  • Амперсанд, за которым следует знак минус (&-). Дескриптор файла будет закрыт. Примечание: это может привести к ошибке программы, поскольку ее записи будут неуспешными.

Для удобства перенаправление &> можно использовать для перенаправления как stdout, так и stderr в одно и то же место назначения. Например, echo hello &> all_output.txt перенаправляет stdout и stderr в файл all_output.txt. Это эквивалентно echo hello > all_output.txt 2>&1.

Любой произвольный дескриптор файла может использоваться в перенаправлении, если перед перенаправлением указать номер 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"

Перенаправление встроенной функции или блока на дескриптор файла с номером больше 2 является ошибкой. Однако это поддерживается для внешних команд.

[1]

Предыдущие версии fish также позволяли указать это как ^DESTINATION, но это делало еще один символ специальным, поэтому он был устаревшим и удален. См. флаги.

Пайпинг

Другой способ перенаправления потоков — пайпинг. Пайпинг соединяет потоки друг с другом. Обычно стандартный вывод одной команды соединяется со стандартным вводом другой. Это делается путем разделения команд символом пайпа |. Например:

cat foo.txt | head

Команда cat foo.txt отправляет содержимое foo.txt в stdout. Этот вывод подается на вход программе head которая выводит первые 10 строк своего ввода.

Можно перенаправить другой дескриптор вывода, добавив его номер FD и символ перенаправления вывода к пайпу. Например:

make fish 2>| less

попытается создать fish, а любые ошибки будут отображаться с помощью программы просмотра less. [2]

Для удобства пайп &| перенаправляет stdout и stderr в один и тот же процесс. Это отличается от bash, который использует |&.

[2]

Программа просмотра — это программа, которая принимает вывод и «странирует» его. less не просто выполняет постраничный вывод, она позволяет произвольное прокручивание (даже назад!).

Управление задачами

При запуске задачи в fish, сам fish приостанавливается и передает управление терминалом только что запущенной программе. Иногда вы хотите продолжить использование командной строки и запустить задачу в фоновом режиме. Для создания фоновой задачи добавьте & (амперсанд) к вашей команде. Это сообщит fish о запуске задачи в фоновом режиме. Фоновые задачи очень полезны при работе с программами, имеющими графический интерфейс пользователя.

Пример:

emacs &

запустит текстовый редактор emacs в фоновом режиме. fg может быть использован для возвращения его в фоновый режим при необходимости.

Большинство программ позволяют приостановить выполнение программы и вернуть управление fish, нажав Ctrl+Z (также известное как ^Z). После возвращения в командную строку fish вы можете запустить другие программы и сделать всё, что захотите. Если затем вы захотите вернуться к приостановленной команде, используйте команду fg (фоновый режим).

Если вы хотите поместить приостановленную задачу в фоновый режим, используйте команду bg.

Чтобы получить список всех текущих запущенных задач, используйте команду jobs. Эти перечисленные задачи могут быть удалены с помощью команды disown.

В данный момент функции не могут быть запущены в фоновом режиме. Функции, которые остановлены, а затем перезапущены в фоновом режиме с помощью команды bg, не будут выполняться корректно.

Если символ & следует неразделяющий символ, он не интерпретируется как оператор фонового режима. Разделяющие символы — это пробелы и символы ;<>&|.

Функции

Функции — это программы, написанные на синтаксисе fish. Они объединяют различные команды и их аргументы под одним именем.

Например, вот простая функция для перечисления каталогов:

function ll
    ls -l $argv
end

Первая строка сообщает fish о определении функции под именем ll, чтобы она могла быть использована, просто написав ll в командной строке. Вторая строка сообщает fish, что команда ls -l $argv должна быть вызвана при вызове ll. $argv — это переменная списка, которая всегда содержит все аргументы, отправленные в функцию. В приведённом примере они просто передаются команде ls. end в третьей строке завершает определение.

Вызов этого как ll /tmp/ приведёт к запуску ls -l /tmp/, который выведет содержимое /tmp.

Это своего рода функция, известная как псевдоним.

Промт fish также определён в функции, называемой 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. Это сохранит её в файле функции, который fish будет автоматически загружать при необходимости.

Встроенная команда functions может отобразить текущее определение функции (и type также сделает это, если ей передана функция).

Для получения дополнительной информации о функциях см. документацию по встроенной команде function.

Определение псевдонимов

Одно из наиболее распространённых применений функций — незначительное изменение поведения уже существующей команды. Например, можно переопределить команду ls для отображения цветов. Переключатель для включения цветов в системах GNU — --color=auto. Псевдоним для команды ls может выглядеть так:

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

Есть несколько важных моментов, которые следует отметить о псевдонимах:

  • Всегда следите за тем, чтобы добавить переменную $argv в список параметров обернутой команды. Это гарантирует, что если пользователь указывает дополнительные параметры функции, они будут переданы базовой команде.
  • Если у псевдонима то же имя, что и у псевдонизируемой команды, вам необходимо добавить префикс command к вызову программы, чтобы сообщить fish, что функция не должна вызывать себя, а вызывать команду с тем же именем. Если вы забудете это сделать, функция будет вызывать себя до бесконечности. Обычно fish достаточно умён, чтобы разобраться с этим и воздержится от этого (что, надеюсь, в ваших интересах).

Для простого создания функции такой формы вы можете использовать команду alias. В отличие от других оболочек, она просто создаёт функции — у fish нет отдельного понятия «псевдонима», мы просто используем это слово для простой оборачивающей функции, как эта. alias сразу же создаёт функцию. Рассмотрите возможность использования alias --save или funcsave для сохранения созданной функции в файл автоматической загрузки вместо повторного создания псевдонима каждый раз.

В качестве альтернативы попробуйте сокращения. Это слова, которые расширяются при вводе, а не являются фактическими функциями внутри оболочки.

Автозагрузка функций

Функции могут быть определены в командной строке или в файле конфигурации, но они также могут загружаться автоматически. Это имеет некоторые преимущества:

  • Автозагружаемая функция становится доступной автоматически для всех запущенных оболочек.
  • Если определение функции изменено, все запущенные оболочки автоматически перезагрузят изменённую версию после некоторого времени.
  • Улучшается время запуска и использование памяти и т. д.

Когда fish необходимо загрузить функцию, она ищет все каталоги в переменной списка $fish_function_path для файла с именем, состоящим из имени функции и суффикса .fish, и загружает первый найденный.

Например, если вы попытаетесь выполнить что-то под названием banana, fish пройдёт по всем каталогам в $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.
  • Функции, поставляемые с fish, обычно установленные в /usr/share/fish/functions (на самом деле $__fish_data_dir/functions).

Если вы не уверены, ваши функции, вероятно, находятся в ~/.config/fish/functions.

Как мы уже объяснили, файлы автоматической загрузки загружаются по имени, поэтому, хотя вы можете поместить несколько функций в один файл, файл будет загружаться автоматически только после попытки выполнить ту, которая имеет то же имя.

Автозагрузка также не будет работать для обработчиков событий, так как fish не может знать, что функция должна быть выполнена при возникновении события, если она ещё не загружена. См. раздел обработчики событий для получения дополнительной информации.

Если файл с нужным именем не определяет функцию, fish не будет читать другие файлы автоматической загрузки, а вместо этого продолжит попытку поиска в встроенных командах и, наконец, в командах. Это позволяет маскировать функцию, определённую позже в $fish_function_path, например, если ваш администратор поместил что-то в /etc/fish/functions, что вы хотите пропустить.

Если вы разрабатываете другую программу и хотите установить функции fish для неё, установите их в каталог функций «vendor». Поскольку этот путь варьируется от системы к системе, вы можете использовать pkgconfig для его обнаружения с помощью вывода pkg-config --variable functionsdir fish. Ваша система установки должна поддерживать пользовательский путь для переопределения пути pkgconfig, поскольку другим дистрибутивам может потребоваться легко его изменить.

Комментарии

Всё после # до конца строки является комментарием. Это значит, что он предназначен только для читателя, fish его игнорирует.

Это полезно для объяснения того, что и почему вы делаете:

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.

Условные операторы

В Fish есть встроенные команды, которые позволяют выполнить команды только в случае выполнения определённого условия: if, switch, and и or, а также знакомый синтаксис &&/||.

Команда switch используется для выполнения одного из нескольких блоков команд в зависимости от значения строки. Более подробная информация доступна в документации по команде switch.

Другие условные операторы используют код возврата (статус выхода) команды для определения, следует ли выполнить команду или блок команд.

В отличие от языков программирования, которые вам известны, команда if не принимает условие, а принимает команду. Если эта команда возвращает успешный код возврата (это 0), то выполняется ветвь if, в противном случае — ветвь else.

Для проверки условия используется команда test:

if test 5 -gt 2
    echo Yes, five is greater than two
end

Некоторые примеры:

# Just see 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 `-q` switch stops it from printing any matches.
if grep -q fish myanimals
    echo "You have fish!"
else
    echo "You don't have fish!"
end

# $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

Обратите внимание, что комбинирующие операторы ленивые — выполняется только та часть, которая необходима для определения конечного статуса.

Сравните:

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

Эти операторы выполняют по существу одно и то же, но первый вариант занимает на 2 секунды больше, потому что sleep всегда необходимо выполнить. Поэтому в таких случаях порядок выполнения имеет значение для производительности.

Или у вас может быть случай, когда необходимо остановить выполнение раньше:

if command -sq foo; and foo

Если бы этот код продолжал выполняться после того, как выяснилось, что команда «foo» не существует, он попытался бы выполнить foo и получил бы ошибку, так как команда не найдена!

Дополнительную информацию можно найти в документации по встроенным командам или в разделе «Условные операторы» в руководстве.

Циклы и блоки

Как и большинство языков программирования, Fish имеет знакомые циклы while и for.

while работает как повторяющийся условный оператор if:

while true
    echo Still running
    sleep 1
end

будет выводить «Still running» раз в секунду. Вы можете прервать выполнение с помощью ctrl-c.

Циклы for работают так же, как и в других оболочках, что больше похоже на циклы for в Python, чем, например, в 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

Расширение параметров

При выполнении команды в fish, параметры расширяются перед отправкой их в команду. Существуют различные виды расширений:

  • Подстановки шаблонов, для создания имён файлов из шаблонов - *.jpg
  • Расширение переменных, для использования значения переменной - $HOME
  • Подстановка команд, для использования вывода другой команды - $(cat /path/to/file)
  • Расширение фигурных скобок, для записи списков с общими префиксами или суффиксами более кратко {/usr,}/bin
  • Расширение тильды, для преобразования ~ в начале путей в путь к домашнему каталогу ~/bin

Расширение параметров ограничено 524288 элементами. Существует ограничение на количество аргументов, которое операционная система допускает для любой команды, и 524288 значительно превышает это ограничение. Это мера, чтобы предотвратить зависание оболочки при выполнении бесполезных вычислений.

Подстановки шаблонов («Глоббинг»)

Когда параметр содержит незакрытую * звездочку (или «звездочку») или ? знак вопроса, fish использует их как подстановки шаблонов для сопоставления файлов.

  • * соответствует любому количеству символов (включая ноль) в имени файла, за исключением /.
  • ** соответствует любому количеству символов (включая ноль) и также спускается в подкаталоги. Если ** является отдельным сегментом, этот сегмент может сопоставляться нулевое количество раз для совместимости с другими оболочками.
  • ? может соответствовать любому одиночному символу, за исключением /. Это устарело и может быть отключено с помощью qmark-noglob флага функции, так что ? будет просто обычным символом.

Сопоставления с подстановками шаблонов сортируются без учета регистра. При сортировке совпадений, содержащих числа, они сортируются в естественном порядке, так что строки ‘1’ ‘5’ и ‘12’ будут отсортированы как 1, 5, 12.

Скрытые файлы (имена которых начинаются с точки) не учитываются при подстановке шаблонов, если в строке подстановки шаблона нет точки в соответствующем месте.

Примеры:

  • a* соответствует любым файлам, начинающимся с ‘a’ в текущем каталоге.
  • ** соответствует любым файлам и каталогам в текущем каталоге и всех его подкаталогах.
  • ~/.* соответствует всем скрытым файлам (также известным как «dotfiles») и каталогам в вашем домашнем каталоге.

Для большинства команд, если какая-либо подстановка шаблона не расширится, команда не выполняется, $status устанавливается в ненулевое значение, и выводится сообщение об ошибке. Это поведение аналогично тому, что делает bash с shopt -s failglob. Существуют исключения, а именно set и path, перезаписывающие переменные в перезаписах, count и for. Их подстановки шаблонов вместо этого будут расширяться до нуля аргументов (так что команда вообще их не увидит), как в shopt -s nullglob в bash.

Примеры:

# 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 (по умолчанию), fish не будет передавать литеральные символы подстановки шаблонов, если совпадение не найдено, поэтому для команды, такой как apt install, которая выполняет сопоставление сама, необходимо добавить кавычки:

apt install "ncurses-*"

Расширение переменных

Одно из самых важных расширений в fish — «расширение переменных». Это замена символа доллара ($) и имени переменной её _значением_.

В простейшем случае это выглядит так:

echo $HOME

что заменит $HOME на домашний каталог текущего пользователя и передаст его команде echo, которая затем выведет его.

Некоторые переменные, такие как $HOME, уже заданы, потому что fish устанавливает их по умолчанию или потому что родительский процесс fish передал их fish при запуске.

Вы можете определить свои собственные переменные, задавая их с помощью 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

Без кавычек или фигурных скобок fish попытается расширить переменную с именем $WORDs, которая может не существовать.

Последний синтаксис {$WORD} является частным случаем расширения фигурных скобок.

Если $WORD здесь не определена или является пустым списком, «s» не выводится. Однако она выводится, если $WORD — это пустая строка (например, после set WORD "").

Дополнительную информацию о переменных оболочки см. в разделе Переменные оболочки.

Цитирование переменных

В отличие от всех остальных расширений, расширение переменных также происходит в двойных кавычках. В двойных кавычках ("these") переменные всегда расширяются ровно до одного аргумента. Если они пустые или не определены, результатом будет пустая строка. Если они содержат один элемент, они расширяются до этого элемента. Если у них более одного элемента, элементы объединяются пробелами, если переменная не является переменной пути — в этом случае она использует двоеточие (:) вместо [3].

За пределами двойных кавычек переменные расширятся до столько аргументов, сколько у них элементов. Это означает, что пустой список расширится до ничего, переменная с одним элементом расширится до этого элемента, а переменная с несколькими элементами расширится до каждого из этих элементов по отдельности.

Если переменная расширяется до ничего, она отменяет любые другие присоединённые к ней строки. Дополнительную информацию см. в разделе декартово произведение.

В отличие от других оболочек, fish не выполняет «разделение слов». После того, как переменной назначен определённый набор элементов, эти элементы расширяются как есть. Они не разбиваются на пробелы или символы новой строки или что-либо ещё:

> set foo one\nthing
> echo $foo
one
thing
> printf '|%s|\n' $foo
|one
thing|

Это означает, что цитирование не является абсолютной необходимостью, как в других оболочках. В большинстве случаев опускание кавычек правильно. Исключение составляют случаи, когда необходимо гарантировать, что переменная передаётся как один элемент, даже если она не задана или содержит несколько элементов. Это часто происходит с командой 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].

При использовании этой функции вместе с квадратными скобками квадратные скобки будут использоваться изнутри наружу. $$foo[5] будет использовать пятый элемент $foo как имя переменной, а не пятый элемент всех переменных, к которым относится $foo. Это вместо этого выражается как $$foo[1..-1][5] (взять все элементы $foo, использовать их как имена переменных, затем получить пятый элемент этих переменных).

Подстановка команд

Вывод команды (или целой цепочки команд) может использоваться в качестве аргументов другой команде.

Когда вы пишете команду в скобках, например outercommand (innercommand), fish сначала выполняет innercommand, а затем использует каждую строку её вывода как отдельный аргумент для outercommand, который затем будет выполнен. В отличие от других оболочек, значение $IFS не используется [4], fish выполняет разделение по символам новой строки.

Подстановка команды может иметь знак доллара перед открывающей скобкой, например outercommand $(innercommand). Этот вариант также разрешён внутри двойных кавычек. При использовании двойных кавычек вывод команды не разбивается на строки, но хвостовые пустые строки всё равно удаляются.

Если вывод направлен на разделение строк или разделение строк с нулевым разделителем как последняя операция, эти разделения используются так, как они появляются, вместо разделения по строкам.

Код состояния последней выполненной подстановки команды доступен в переменной состояние, если подстановка происходит в контексте команды set (например, if set -l (something) проверяет, вернула ли something значение true).

Для использования только некоторых строк вывода, обратитесь к расширению диапазона индексов.

Примеры:

# 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

но если вам нужно несколько файлов или команда не читает со стандартного ввода, полезна «подстановка процесса». Другие оболочки позволяют это с помощью foo <(bar) <(baz), а fish использует команду psub:

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

Это создаёт временный файл, сохраняет вывод команды в этом файле и выводит имя файла, чтобы его получила внешняя команда.

Fish имеет стандартный лимит в 100 МБ на данные, которые будут считываться в подстановке команды. Если этот лимит достигнут, команда (вся, а не только подстановка команды - внешняя команда вообще не будет выполнена) завершается ошибкой, и $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, just like a bare `echo`.

Если между фигурной скобкой и запятой или двумя запятыми ничего нет, это интерпретируется как пустой элемент:

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

Чтобы использовать «,» как элемент, цитируйте или экранируйте его.

Объединение списков (Декартово произведение)

Когда списки расширяются с присоединёнными к ним другими частями, они расширяются с этими частями. Даже если два списка присоединены друг к другу, они расширяются во всех комбинациях. Это называется «декартовым произведением» (как в математике), и работает в основном так же, как и расширение фигурных скобок.

Примеры:

# Brace expansion is the most familiar:
# All elements in the brace combine with the parts outside of the braces
>_ echo {good,bad}" apples"
good apples bad apples

# The same thing happens with variable expansion.
>_ set -l a x y z
>_ set -l b 1 2 3

# $a is {x,y,z}, $b is {1,2,3},
# so this is `echo {x,y,z}{1,2,3}`
>_ echo $a$b
x1 y1 z1 x2 y2 z2 x3 y3 z3

# Same thing if something is between the lists
>_ echo $a"-"$b
x-1 y-1 z-1 x-2 y-2 z-2 x-3 y-3 z-3

# Or a brace expansion and a variable
>_ echo {x,y,z}$b
x1 y1 z1 x2 y2 z2 x3 y3 z3

# A combined brace-variable expansion
>_ echo {$b}word
1word 2word 3word

# Special case: If $c has no elements, this expands to nothing
>_ echo {$c}word
# Output is an empty line

Иногда это может быть нежелательно, особенно потому, что токены могут исчезнуть после расширения. В таких случаях вы должны заключить переменные в двойные кавычки - 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

Это может быть очень полезно. Например, если вы хотите пройтись по всем файлам во всех каталогах в PATH, используйте

for file in $PATH/*

Так как PATH является списком, это расширяется до всех файлов во всех каталогах в нём. И если в PATH нет каталогов, правильный ответ здесь - расшириться до нуля файлов.

Расширение диапазона индексов

Иногда необходимо получить доступ только к некоторым элементам списка (все переменные fish являются списками) или к некоторым строкам вывода подстановки команды. В fish это возможно, написав набор индексов в квадратных скобках, например:

# 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"

В квадратных скобках fish понимает диапазоны, записанные как a..b («a» и «b» — это индексы). Они расширяются в последовательность индексов от a до b (например, a a+1 a+2 ... b), увеличиваясь, если b больше, и уменьшаясь, если a больше. Также могут использоваться отрицательные индексы — они берутся с конца списка, поэтому -1 — это последний элемент, а -2 — элемент перед ним. Если индекс не существует, диапазон обрезается до ближайшего возможного индекса.

Если у списка 5 элементов, индексы идут от 1 до 5, поэтому диапазон 2..16 будет охватывать только элементы с 2 по 5.

Если конечный индекс отрицательный, диапазон всегда увеличивается, поэтому 2..-2 будет охватывать элементы с 2 по 4, а 2..-16 не пойдёт никуда, потому что нет возможности перейти от второго элемента к несуществующему, двигаясь вверх. Если начальный индекс отрицательный, диапазон всегда уменьшается, поэтому -2..1 будет охватывать элементы с 4 по 1, а -16..2 никуда не пойдёт, потому что нет возможности перейти от несуществующего элемента ко второму элементу, двигаясь вниз.

Пропущенный начальный индекс в диапазоне по умолчанию равен 1. Это разрешено, если диапазон является первым выражением индекса в последовательности. Аналогично, пропущенный конечный индекс по умолчанию равен -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.

Переменные оболочки

Переменные — это способ сохранения данных и передачи их. Они могут использоваться только оболочкой, или могут быть «экспортированы», так что копия переменной доступна для любого внешнего командного интерпретатора, который запустила оболочка. Экспортированная переменная называется «переменной среды».

Для установки значения переменной используйте команду set. Имя переменной не может быть пустым и может содержать только буквы, цифры и символы нижнего подчеркивания. Оно может начинаться и заканчиваться любым из этих символов.

Пример:

Чтобы установить переменную 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, и используете её с $ и именем.

Область действия переменных

В fish существуют четыре типа переменных: универсальные, глобальные, локальные и переменные функций.

  • Универсальные переменные разделяются между всеми сессиями fish, которые пользователь запускает на одном компьютере.
  • Глобальные переменные специфичны для текущей сессии fish и никогда не будут удалены, если явно не запросить их удаление, используя set -e.
  • Переменные функций специфичны для выполняемой в данный момент функции. Они удаляются («выходят из области видимости») по завершении текущей функции. За пределами функции они не выходят из области видимости.
  • Локальные переменные специфичны для текущей группы команд и автоматически удаляются, когда область видимости конкретной группы команд выходит из неё. Группа команд — это последовательность команд, начинающаяся с одной из команд 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

Если вы хотите установить личную настройку, универсальные переменные хороши:

# Typically you'd run this interactively, fish takes care of keeping it.
set -U fish_color_autosuggestion 555

Вот пример локальных и переменных с областью видимости функции:

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

    echo $pirate
    # This will not output anything, since the pirate was local
    echo $captain
    # This will output the good Captain's speech since $captain had function-scope.
    echo $gnu
    # Will output Sir Terry's wisdom.
end

В случае сомнений используйте переменные с областью видимости функции. Когда вам нужно сделать переменную доступной везде, сделайте её глобальной. Когда нужно хранить конфигурацию постоянно, сделайте её универсальной. Когда вы хотите использовать переменную только в короткой группе команд, сделайте её локальной.

Переопределение переменных для одной команды

Если вы хотите переопределить переменную для одной команды, вы можете использовать инструкции «var=val» перед командой:

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

В отличие от других оболочек, fish сначала установит переменную, а затем выполнит другие расширения в строке, поэтому:

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

Или с помощью шаблона:

# 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

В отличие от других оболочек, это не препятствует поиску (псевдонимы и т. п.). Вызов команды после установки переопределения переменной приведет к запуску точно такой же команды.

Этот синтаксис поддерживается начиная с fish 3.1.

Подробнее об универсальных переменных

Универсальные переменные — это переменные, которые разделяются между всеми сессиями fish пользователя на компьютере. Fish хранит многие свои параметры конфигурации в виде универсальных переменных. Это означает, что для изменения настроек fish вам нужно изменить значение переменной один раз, и оно будет автоматически обновлено для всех сессий и сохранится при перезагрузке компьютера и входа/выхода.

Чтобы увидеть универсальные переменные в действии, запустите две сессии fish рядом и выполните следующую команду в одной из них set fish_color_cwd blue. Поскольку fish_color_cwd — универсальная переменная, цвет отображения текущего каталога в приглашении моментально изменится на синий в обоих терминалах.

Универсальные переменные хранятся в файле .config/fish/fish_variables. Не редактируйте этот файл напрямую, так как ваши изменения могут быть перезаписаны. Редактируйте переменные через скрипты fish или с помощью интерактивного режима fish.

Не добавляйте в универсальные переменные в config.fish, потому что эти переменные будут становиться длиннее с каждым новым экземпляром оболочки. Вместо этого просто установите их один раз в командной строке.

Область видимости переменных для функций

При вызове функции все текущие локальные переменные временно исчезают. Это затемнение локальной области видимости необходимо, так как пространство имён переменных станет переполненным, что очень легко приведёт к случайной перезаписи переменных из другой функции.

Например:

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
    shiver
    echo $phrase
end
avast

# Outputs "Avast, mateys"

Экспорт переменных

Переменные в fish могут быть экспортированы, поэтому они будут унаследованы любыми командами, запущенными fish. В частности, это необходимо для переменных, используемых для настройки внешних команд, таких как PAGER или GOPATH, а также для переменных, содержащих общие системные настройки, такие как PATH или LANGUAGE. Если внешней команде нужна переменная, её нужно экспортировать. Экспортированные переменные также часто называют «переменными среды».

Это также относится к fish — при запуске он получает переменные среды от своего родителя (обычно терминала). Они обычно включают системную конфигурацию, такую как PATH и переменные локали.

Переменные могут быть явно установлены для экспорта с помощью переключателей -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 "-"

Примечание: экспорт не является областью видимости, но дополнительным состоянием. Обычно имеет смысл делать экспортированные переменные глобальными, но локально-экспортированные переменные могут быть полезны, если вам нужно что-то более конкретное, чем Переопределения. Они копируются в функции, поэтому функция не может их изменить снаружи, и всё ещё доступны командам. Глобальные переменные доступны функциям, экспортированы они или нет.

Списки

Рыба может хранить список (или «массив», если хотите) из нескольких строк внутри переменной:

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

Для доступа к одному элементу списка используйте индекс элемента в квадратных скобках, например:

echo $PATH[3]

Индексы списков в рыбе начинаются с 1, а не с 0, как в других языках. Это потому, что это требует меньше вычитаний 1, и многие общие утилиты Unix, такие как seq работают лучше с этим (seq 5 выводит от 1 до 5, а не от 0 до 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

Как видите, вы можете использовать диапазон индексов, см. расширение диапазона индексов для подробностей.

Все списки одномерные и не могут содержать другие списки, хотя можно имитировать вложенные списки с помощью обращений — см. расширение переменных.

При экспорте списка в качестве переменной среды он разделяются пробелами или двоеточиями, в зависимости от того, является ли он переменной пути:

> 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"` .

В отличие от других оболочек, рыба не выполняет «разбиение слов» — элементы списка остаются такими, какие они есть, даже если они содержат пробелы или табуляции.

Обработка аргументов

Важный список — $argv, который содержит аргументы функции или скрипта. Например:

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

Эта функция принимает любые переданные аргументы и выводит первый и третий:

> myfunction first second third
first
third

> myfunction apple cucumber banana
apple
banana

Это касается позиционных аргументов, но утилиты командной строки часто получают различные опции и флаги, и $argv будет содержать их вместе с позиционными аргументами. Типичная обработка аргументов Unix допускает короткие опции (-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

Переменные пути — это специальный вид переменных, используемых для поддержки списков путей с разделителями двоеточием, включая PATH, CDPATH, MANPATH, PYTHONPATH, и т. д. По умолчанию все переменные, заканчивающиеся на «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

Это сделано для совместимости с другими инструментами. В Unix нет переменных с несколькими элементами, ближайшая аналогия — списки с разделителями двоеточиями, такие как PATH. По понятным причинам это означает, что ни один элемент не может содержать :.

Переменные можно помечать или снимать пометку как переменные PATH с помощью опций --path и --unpath для set.

Специальные переменные

Вы можете изменить настройки fish, изменив значения определенных переменных.

PATH

Список каталогов, в которых следует искать команды. Это общая переменная Unix, используемая и другими инструментами.

CDPATH

Список каталогов, в которых встроенная команда cd ищет новый каталог.

Переменные локали

Переменные локали LANG, LC_ALL, LC_COLLATE, LC_CTYPE, LC_MESSAGES, LC_MONETARY, LC_NUMERIC и LANG устанавливают языковой параметр для оболочки и подпрограмм. Дополнительную информацию см. в разделе Переменные локали.

Переменные цвета

Несколько переменных, начинающихся с префиксов fish_color и fish_pager_color. Дополнительную информацию см. в разделе Переменные для изменения цветов выделения.

fish_ambiguous_width

управляет вычисляемой шириной символов с неоднозначной шириной. Это должно быть установлено в 1, если ваша терминальная оболочка отображает эти символы как символы одинарной ширины (обычное дело), или в 2, если двойной ширины.

fish_emoji_width

управляет тем, считает ли fish, что эмодзи отображаются как 2 ячейки или 1 ячейка в ширину. Это необходимо, потому что правильное значение изменилось с 1 на 2 в Unicode 9, и некоторые терминалы могут этого не учитывать. Установите это, если вы видите графические артефакты, связанные с эмодзи (или другими «специальными» символами). Обычно это должно автоматически определяться.

fish_autosuggestion_enabled

управляет тем, включены ли Автопредложения. Установите значение 0, чтобы отключить, любое другое значение — чтобы включить. По умолчанию они включены.

fish_handle_reflow

определяет, должен ли fish пытаться перерисовать командную строку при изменении размеров терминала. В терминалах, которые перестраивают текст, это должно быть отключено. Установите значение 1, чтобы включить, любое другое значение — чтобы отключить.

fish_key_bindings

имя функции, которая настраивает сочетания клавиш для редактора командной строки.

fish_escape_delay_ms

устанавливает, сколько времени fish ожидает следующей клавиши после обнаружения клавиши Escape, чтобы отличить нажатие клавиши Escape от начала последовательности Escape. Значение по умолчанию составляет 30 мс. Увеличение этого значения увеличивает задержку, но позволяет нажимать Escape вместо Alt для сочетаний Alt+символ. Дополнительную информацию см. в главе в документации по bind.

fish_complete_path

определяет, где fish ищет завершение. При попытке завершить команду fish ищет файлы в каталогах в этой переменной.

fish_cursor_selection_mode

управляет тем, является ли выбор включительно или исключительным по отношению к символу под курсором (см. Копирование и вставка).

fish_function_path

определяет, где fish ищет функции. Когда fish автоматически загружает функцию, он будет искать файлы в этих каталогах.

fish_greeting

сообщение приветствия, отображаемое при запуске. Это печатает функция с тем же именем, которую можно переопределить для более сложных изменений (см. funced)

fish_history

название текущей сессии истории. Если установлено, все последующие команды в интерактивной сессии fish будут регистрироваться в отдельном файле, идентифицируемом по значению переменной. Если не установлено, используется имя сессии по умолчанию «fish». Если установлено значение пустой строки, история не сохраняется на диск (но по-прежнему доступна в интерактивной сессии).

fish_trace

если установлено и не пусто, заставит fish печатать команды перед их выполнением, аналогично set -x в bash. Отслеживание выводится в путь, указанный параметром --debug-output к fish или переменной FISH_DEBUG_OUTPUT. По умолчанию выводится в stderr.

FISH_DEBUG

Управляет категориями отладки, которые fish включает для вывода, аналогично параметру --debug.

FISH_DEBUG_OUTPUT

Указывает файл для вывода отладочной информации.

fish_user_paths

Список каталогов, которые добавляются перед PATH. Это может быть универсальная переменная.

umask

Текущая маска создания файла. Предпочтительный способ изменения переменной umask — через функцию umask. Попытка установить umask с недопустимым значением всегда завершится неудачей.

BROWSER

ваш предпочтительный веб-браузер. Если эта переменная установлена, fish будет использовать указанный браузер вместо системного браузера по умолчанию для отображения документации fish.

Fish также предоставляет дополнительную информацию через значения определенных переменных среды. Большинство из этих переменных являются только для чтения и их значение нельзя изменить с помощью set.

_

имя выполняемой в данный момент команды (хотя это устарело, и предпочтительно использовать status current-command).

argv

список аргументов для оболочки или функции. argv определена только при вызове функции или если fish был вызван со списком аргументов, как fish myscript.fish foo bar. Эту переменную можно изменить.

CMD_DURATION

время выполнения последней команды в миллисекундах.

COLUMNS и LINES

текущий размер терминала по высоте и ширине. Эти значения используются fish только если операционная система не сообщает о размере терминала. В этом случае обе переменные должны быть установлены, в противном случае будет использоваться значение по умолчанию 80x24. Они обновляются при изменении размера окна.

fish_kill_signal

сигнал, завершивший последнюю фоновую задачу, или 0, если работа завершилась нормально.

fish_killring

список записей в кольце обмена fish вырезанного текста.

fish_read_limit

количество байтов, которые fish обработает с помощью read или в подстановке команд.

fish_pid

идентификатор процесса (PID) оболочки.

history

список последних введенных команд.

HOME

домашний каталог пользователя. Эту переменную можно изменить.

hostname

имя хоста машины.

IFS

внутренний разделитель полей, используемый для разделения слов с помощью встроенной команды read. Установка его в пустую строку также отключит разделение строк в замене команд. Эта переменная может быть изменена.

last_pid

идентификатор процесса (PID) последнего фонового процесса.

PWD

текущая рабочая директория.

pipestatus

список кодов завершения всех процессов, составляющих последнюю выполненную цепочку команд. См. код завершения.

SHLVL

уровень вложенности оболочек. Fish увеличивает его во взаимодействующих оболочках, в противном случае он просто передаёт его дальше.

status

код завершения последней завершившейся фоновой задачи. Если задача была завершена с помощью сигнала, код завершения будет равен 128 плюс номер сигнала.

status_generation

счётчик «поколения» для $status. Он увеличивается только тогда, когда предыдущая команда возвращает явный код завершения. (Например, фоновые задачи не увеличивают его).

TERM

тип текущего терминала. Когда fish пытается определить, как работает терминал — сколько он поддерживает цветов, какие последовательности отправляет для клавиш и другие вещи — он смотрит на эту переменную и соответствующую информацию в базе данных terminfo (см. man terminfo).

Примечание: обычно это не следует изменять, так как терминал устанавливает его в правильное значение.

USER

текущее имя пользователя. Эта переменная может быть изменена.

EUID

текущий эффективный идентификатор пользователя, установленный fish при запуске. Эта переменная может быть изменена.

version

версия текущей работающей fish (также доступна как FISH_VERSION для обратной совместимости).

По соглашению, для экспортируемых переменных обычно используется имя с заглавными буквами, а для неэкспортируемых — с маленькими. (CMD_DURATION является исключением по историческим причинам). Это правило не навязывается fish, но хорошая практика — использовать регистр для различения экспортируемых и неэкспортируемых переменных.

Fish также использует некоторые переменные внутри, их имена обычно начинаются с __fish. Эти переменные являются внутренними и обычно не следует изменять напрямую.

Переменная состояния

Всякий раз, когда процесс завершается, программе, которая его запустила (обычно оболочке), возвращается код завершения. Этот код завершения — целое число, которое указывает вызывающему приложению, как прошло выполнение команды. В общем, код завершения 0 означает, что команда выполнилась без проблем, а ненулевой код завершения означает, что возникла какая-то проблема.

Fish сохраняет код завершения последнего процесса в последней завершившейся задаче в переменной status.

Если fish сталкивается с проблемой во время выполнения команды, переменная состояния также может быть установлена в определённое значение:

  • 0 обычно является кодом завершения команд, если они успешно выполнили запрошенную операцию.
  • 1 обычно является кодом завершения команд, если они не смогли выполнить запрошенную операцию.
  • 121 обычно является кодом завершения команд, если они были предоставлены некорректными аргументами.
  • 123 означает, что команда не была выполнена, потому что имя команды содержало недопустимые символы.
  • 124 означает, что команда не была выполнена, потому что ни один из подстановочных знаков в команде не дал совпадений.
  • 125 означает, что хотя исполняемый файл с заданным именем был найден, операционная система не смогла выполнить команду.
  • 126 означает, что хотя файл с заданным именем был найден, он не был исполняемым.
  • 127 означает, что ни функция, ни встроенная команда, ни команда с заданным именем не были найдены.

Если процесс завершается из-за сигнала, код завершения будет равен 128 плюс номер сигнала.

Состояние можно инвертировать с помощью 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 будет 1 из-за not, а $pipestatus будут 0 и 0.

Возможно, что первая команда завершится с ошибкой, а вторая — успешно. Один из распространенных примеров — когда вторая программа завершается слишком рано.

Например, если у вас есть цепочка команд:

cat file1 file2 | head -n 50

Это позволит cat вывести два файла, «file1» и «file2», один за другим, а head затем выведет только первые 50 строк. В этом случае вы часто можете встретить такую конфигурацию:

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

Здесь «141» означает, что cat был прерван сигналом с номером 13 (128 + 13 == 141) — SIGPIPE. Также можно использовать fish_kill_signal, чтобы увидеть номер сигнала. Это происходит потому, что он всё ещё работал, а затем head закрыл цепочку команд, поэтому cat получил сигнал, который не проигнорировал, и поэтому завершился.

Будет ли cat здесь получать SIGPIPE, зависит от длины файла и того, сколько он пишет за раз, поэтому вы можете увидеть pipestatus «0 0», в зависимости от реализации. Это общая проблема Unix, а не специфичная для fish. Некоторые оболочки имеют функцию «pipefail», которая отмечает цепочку команд как невыполненную, если один из процессов в ней завершился с ошибкой, и это большая проблема с ней.

Локальные переменные

«Локаль» программы — это набор языковых и региональных настроек, зависящих от языка и культурных традиций. В UNIX они состоят из нескольких категорий.

LANG

Это типичная переменная окружения для указания локали. Пользователь может установить эту переменную, чтобы указать язык, регион и кодировку символов. Фактические значения зависят от платформы, за исключением специальных значений, таких как C или POSIX.

Значение LANG используется для каждой категории, если переменная для этой категории не была установлена или LC_ALL установлена. Так что обычно вам нужно установить только LANG.

Пример значения может быть en_US.UTF-8 для американской версии английского и кодировки UTF-8 или de_AT.UTF-8 для австрийской версии немецкого и кодировки UTF-8. Ваша операционная система, возможно, имеет команду locale, которую вы можете вызвать как locale -a, чтобы увидеть список определённых локалей.

Рекомендуется использовать кодировку UTF-8.

LC_ALL

Переопределяет переменную окружения LANG и значения других переменных LC_*. Если она установлена, другие переменные не используются.

Обычно следует использовать другие переменные вместо неё. Используйте LC_ALL только когда вам нужно переопределить что-то.

LC_COLLATE

Это определяет правила эквивалентности регистров и алфавитного упорядочения: сортировка.

LC_CTYPE

Это определяет правила классификации, такие как определение, является ли символ буквой, цифрой и так далее. Самое главное, что она определяет кодировку текста — какие числа соответствуют каким символам. В современных системах это обычно должно быть что-то, заканчивающееся на «UTF-8».

LC_MESSAGES

LC_MESSAGES определяет язык, на котором отображаются сообщения.

LC_MONETARY

Определяет валюту, её формат и используемые символы.

LC_NUMERIC

Устанавливает локаль для форматирования чисел.

LC_TIME

Устанавливает локаль для форматирования дат и времени.

Встроенные команды

Fish включает ряд команд в оболочке напрямую. Мы называем их «встроенными». К ним относятся:

  • Встроенные команды, которые управляют состоянием оболочки - cd изменяет директорию, set задаёт переменные
  • Встроенные команды для работы с данными, такие как string для строк и math для чисел, count для подсчёта строк или аргументов, path для работы с путями
  • status для запроса состояния оболочки
  • printf и echo для создания вывода
  • test для проверки условий
  • argparse для разбора аргументов функций
  • source для чтения скрипта в текущей оболочке (чтобы изменения в переменных сохранились) и eval для выполнения строки как скрипта
  • random для получения случайных чисел или выбора случайного элемента из списка
  • read для чтения из канала или терминала

Для списка всех встроенных команд, используйте builtin -n.

Для получения списка всех встроенных функций и команд, поставляемых с fish, см. список команд. Документация также доступна с помощью переключателя --help.

Поиск команд

Когда fish получает команду на выполнение, он проходит несколько этапов для ее поиска.

Если команда содержит /, fish пытается выполнить указанный файл, начиная с текущей директории.

Если команда не содержит /, она может быть функцией, встроенной командой или внешней командой, и поэтому fish проходит полный поиск.

В порядке:

  1. Он пытается разрешить её как функцию.

    • Если функция уже известна, она используется
    • Если существует файл с таким именем и расширением “.fish” в fish_function_path, он загружается. (Если таких файлов несколько, используется только первый)
    • Если функция теперь определена, она используется
  2. Он пытается разрешить её как встроенную команду.
  3. Он пытается найти исполняемый файл в PATH.

    • Если файл найден, он сообщает ядру о запуске файла.
    • Если ядро знает, как запустить файл (например, через строку #! - #!/bin/sh или #!/usr/bin/python), оно это делает.
    • Если ядро сообщает, что не может запустить файл из-за отсутствия интерпретатора, и файл проходит упрощенную проверку, fish сообщает /bin/sh о запуске файла.

Если ни один из этих методов не сработал, fish выполняет функцию fish_command_not_found и устанавливает status в 127.

Вы можете использовать type для просмотра того, как fish разрешил что-либо:

> 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 ., возможно, что-то будет напечатано без запроса, потому что файлов меньше пяти.

Имена переменных и функций оболочки

Имена переменных и функций (так называемые «идентификаторы») должны соответствовать определённым правилам:

  • Имя переменной не может быть пустым. Оно может содержать только буквы, цифры и символы подчёркивания. Оно может начинаться и заканчиваться любым из этих символов.
  • Имя функции не может быть пустым. Оно не может начинаться с тире («-») и не может содержать слеш («/»). Все остальные символы, включая пробел, допустимы. Имя функции также не может совпадать с зарезервированным ключевым словом или существенной встроенной командой, например, if или set.
  • Имя режима привязки (например, bind -m abc ...) должно быть допустимым именем переменной.

У других элементов есть свои ограничения. Например, то, что разрешено для имён файлов, зависит от вашей системы, но, по крайней мере, они не могут содержать «/» (потому что это разделитель путей) или нулевой байт (потому что так UNIX завершает строки).

Файлы конфигурации

При запуске fish он считывает и выполняет свои файлы конфигурации. Где они находятся, зависит от конфигурации сборки и переменных среды.

Основной файл — ~/.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 ищет директории в $__fish_user_data_dir (обычно ~/.local/share/fish, управляемая переменной среды XDG_DATA_HOME) и в переменной среды XDG_DATA_DIRS для директории fish/vendor_conf.d; если она не определена, значение по умолчанию XDG_DATA_DIRS равно /usr/share/fish/vendor_conf.d и /usr/local/share/fish/vendor_conf.d, если ваша дистрибуция не изменила это.

    Если в этих директориях есть несколько файлов с одинаковым именем, будет выполнен только первый. Они выполняются в порядке их имён файлов, отсортированных (как в glob) в естественном порядке (т.е. «01» сортируется раньше «2»).

  • Системные файлы конфигурации, где администраторы могут включать инициализацию для всех пользователей в системе — аналогично /etc/profile для оболочек в стиле POSIX — в $__fish_sysconf_dir (обычно /etc/fish/config.fish).
  • Конфигурация пользователя, обычно в ~/.config/fish/config.fish (управляемая переменной среды XDG_CONFIG_HOME, и доступная как $__fish_config_dir).

~/.config/fish/config.fish выполняется *после* фрагментов. Это позволяет копировать фрагменты и переопределять некоторые их аспекты.

Эти файлы выполняются при каждом запуске оболочки. Если вы хотите выполнить команду только при запуске интерактивной оболочки, используйте код возврата команды status --is-interactive для определения, является ли оболочка интерактивной. Если вы хотите выполнить команду только при использовании оболочки входа, используйте status --is-login вместо этого. Это ускорит запуск неинтерактивных или нелоговых оболочек.

Если вы разрабатываете другую программу, вам может потребоваться добавить конфигурацию для всех пользователей fish на системе. Это не рекомендуется; если не написаны тщательно, они могут иметь побочные эффекты или замедлить запуск оболочки. Кроме того, пользователи других оболочек не получат преимуществ от специфической конфигурации fish. Однако, если они необходимы, вы можете установить их в директорию конфигурации «vendor». Так как этот путь может варьироваться от системы к системе, следует использовать pkg-config, чтобы обнаружить его: pkg-config --variable confdir fish.

Флаги будущих функций

Флаги функций — это способ изменения стадий работы fish, которые могут нарушить скрипты. Внедряемые изменения вносятся как опциональные, в нескольких выпусках они становятся опциональными по умолчанию, а в конечном итоге старое поведение удаляется.

Вы можете увидеть текущий список функций через status features.

> status features
stderr-nocaret          on  3.0 ^ no longer redirects stderr
qmark-noglob            off 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

Вот что они означают:

  • stderr-nocaret был введён в fish 3.0 (и стал по умолчанию в 3.3). Он делает ^ обычным символом вместо обозначения перенаправления stderr, чтобы упростить работу с цитированием и т. п. Используйте 2> вместо него. С fish 3.5 это больше нельзя отключать. Флаг всё ещё можно проверить на совместимость, но значение no-stderr-nocaret будет просто проигнорировано.
  • qmark-noglob также был введён в fish 3.0. Он делает ? обычным символом вместо символьного шаблона. Используйте * (которое будет соответствовать нескольким символам) или найдите другие способы сопоставления файлов, такие как find.
  • regex-easyesc был введён в 3.1. Он делает так, что выражение замены в string replace -r выполняет на один цикл меньше экранирование. Раньше, чтобы экранировать обратную косую черту, вам нужно было использовать string replace -ra '([ab])' '\\\\\\\\$1'. Теперь достаточно '\\\\$1'. Проверьте свои вызовы string replace, если вы используете их где-либо.
  • ampersand-nobg-in-token был введён в fish 3.4. Он делает так, что & больше не интерпретируется как оператор фонового выполнения в середине токена, что упрощает работу с URL-адресами. Поставьте пробелы или точку с запятой после &. Это рекомендуемый формат, и fish_indent уже сделает это за вас.

Эти изменения включены по умолчанию. Их можно включить на сеанс:

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

или включить глобально для пользователя:

> set -U fish_features regex-easyesc qmark-noglob

Функции будут устанавливаться только при запуске, поэтому эта переменная вступит в силу только если она универсальна или экспортирована.

Вы также можете использовать версию как группу, поэтому 3.0 эквивалентно «stderr-nocaret» и «qmark-noglob». Вместо версии специальная группа all включает все функции.

Представление функции с префиксом no- выключает её. Например, чтобы снова включить ? - шаблон для одного символа:

set -Ua fish_features no-qmark-noglob

В настоящее время по умолчанию включены следующие функции:

  • stderr-nocaret - ^ больше не перенаправляет stderr, используйте 2>. Включено по умолчанию в fish 3.3.0. Не изменяется с fish 3.5.0.
  • regex-easyesc - string replace -r требует меньше обратных косых черт в части замены. Включено по умолчанию в fish 3.5.0.
  • ampersand-nobg-in-token - & в середине слова — это обычный символ, а не фоновое выполнение. Включено по умолчанию в fish 3.5.0.

Обработчики событий

При определении новой функции в fish её можно сделать обработчиком событий, то есть функцией, которая автоматически выполняется при возникновении определённого события. События, которые могут инициировать обработчик, в настоящее время:

  • При получении сигнала
  • При завершении задачи
  • При обновлении значения переменной
  • При отображении приглашения

Пример:

Чтобы указать обработчик сигнала для сигнала WINCH, напишите:

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

Fish уже имеет следующие именованные события для переключателя --on-event:

  • fish_prompt генерируется всякий раз, когда отображается новое приглашение fish.
  • fish_preexec генерируется непосредственно перед выполнением интерактивной команды. Командная строка передаётся в качестве первого параметра. Не генерируется, если команда пустая.
  • fish_posterror генерируется сразу после выполнения команды с синтаксическими ошибками. Командная строка передаётся в качестве первого параметра.
  • fish_postexec генерируется сразу после выполнения интерактивной команды. Командная строка передаётся в качестве первого параметра. Не генерируется, если команда пустая.
  • fish_exit генерируется непосредственно перед завершением работы fish.
  • fish_cancel генерируется при очистке командной строки.

События могут быть вызваны командой 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

Если для события существует несколько обработчиков, они все будут выполнены, но порядок может меняться между выпусками fish, поэтому полагаться на него не следует.

Обратите внимание, что обработчики событий активируются только при загрузке функции, что означает, что вам нужно иначе source или выполнить функцию, а не полагаться на автозагрузку. Один из способов — поместить его в ваш файл конфигурации.

Дополнительную информацию о том, как определять новые обработчики событий, см. в документации для команды function.

Отладка скриптов fish

Fish включает базовые встроенные средства отладки, которые позволяют остановить выполнение скрипта в произвольной точке. При этом вы получаете интерактивное приглашение, где можете выполнить любую команду fish для проверки или изменения состояния (специальных команд отладки нет как таковых). Например, вы можете проверить или изменить значение любых переменных с помощью printf и set. В качестве другого примера, вы можете запустить status print-stack-trace, чтобы увидеть, как был достигнут текущий разрыв. Чтобы продолжить обычное выполнение скрипта, просто введите exit или Ctrl+D.

Чтобы начать сеанс отладки, просто вставьте встроенную команду breakpoint в нужном месте функции или скрипта, а затем запустите функцию или скрипт. Кроме того, стандартное действие сигнала TRAP — это вызов этой встроенной команды, что означает, что запущенный скрипт можно активно отлаживать, отправив ему сигнал TRAP (kill -s TRAP <PID>). Поддержка интерактивного задания или изменения точек останова из этого приглашения отладки ограничена: можно вставлять новые точки останова в (или удалять старые из) других функций с помощью функции funced для редактирования определения функции, но невозможно добавить или удалить точку останова из функции/скрипта, которые в данный момент загружены и выполняются.

Другой способ отладки проблем со скриптами — установить переменную fish_trace, например, fish_trace=1 fish_prompt, чтобы увидеть, какие команды выполняет fish при выполнении функции fish_prompt.

Если вы хотите специально отладить проблемы с производительностью, fish можно запустить с параметром --profile /path/to/profile.log для сохранения профиля в указанном пути. В этом журнале профиля приведён подробный анализ того, сколько времени потребовалось на каждом шаге выполнения. Дополнительную информацию см. в fish.

© 2005-2009 Axel Liljencrantz, 2009-2023 fish-shell contributors
Licensed under the GNU General Public License, version 2.
https://fishshell.com/docs/3.6/language.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API