Spec-Zone.ru › Fish 3.4

Язык командной оболочки fish

Данный документ содержит исчерпывающий обзор скриптового языка командной оболочки fish.

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

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

Командные оболочки, такие как fish, используются для выполнения команд. Команда выполняется путём ввода имени команды, за которым следуют аргументы. Например:

echo hello world

команда echo выводит свои аргументы на экран. В данном примере результат будет hello world.

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

Чтобы узнать больше о команде echo, прочитайте её справку, набрав man echo. Команда man используется для отображения справки по заданной теме. Она принимает имя страницы справки в качестве аргумента. Справки имеются практически для каждой команды. Также есть справки для многих других вещей, таких как системные библиотеки и важные файлы.

Любая программа на вашем компьютере может быть использована как команда в fish. Если файл программы находится в одном из каталогов PATH, вы можете просто ввести имя программы для её запуска. В противном случае требуется указать полное имя файла, включая директорию (например, /home/me/code/checkers/checkers или ../checkers).

Вот список некоторых полезных команд:

  • cd: Изменить текущую директорию
  • ls: Отобразить список файлов и каталогов
  • man: Отобразить справку
  • mv: Переместить (переименовать) файлы
  • cp: Скопировать файлы
  • open: Открыть файлы с помощью приложения по умолчанию, связанного с типом файла
  • less: Отобразить содержимое файлов

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

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

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

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

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

  • Аргумент: Параметр, переданный команде.
  • Встроенная команда: Команда, реализованная в оболочке. Встроенные команды так тесно связаны с работой оболочки, что их невозможно реализовать как внешние команды.
  • Команда: Программа, которую может запустить оболочка, или, точнее, внешняя программа, которую оболочка запускает в другом процессе.
  • Функция: Блок команд, который может быть вызван как единая команда. С помощью функций можно объединить несколько простых команд в одну более сложную.
  • Задача: Запущенная цепочка команд или команда.
  • Цепочка команд: Набор команд, соединённых таким образом, что вывод одной команды является вводом следующей.
  • Перенаправление: Операция, изменяющая один из входных или выходных потоков, связанных с задачей.
  • Флаг или Опция: Специальный вид аргумента, изменяющий поведение команды. Флаг почти всегда начинается с одного или двух тире.

Кавычки

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

Экранирование символов

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

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

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

echo \'hello world\'

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

echo 'hello world'

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

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

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

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

Большинство программ используют три потока ввода/вывода (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.
  • Чтобы не перезаписывать (“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.

Любой произвольный дескриптор файла может использоваться в перенаправлении, добавив его номер перед перенаправлением.

  • Чтобы перенаправить ввод дескриптора N, используйте N<DESTINATION.
  • Чтобы перенаправить вывод дескриптора N, используйте N>DESTINATION.
  • Чтобы добавить вывод дескриптора N в файл, используйте N>>DESTINATION_FILE.

Например, echo hello 2> output.stderr записывает стандартную ошибку (дескриптор файла 2) в output.stderr.

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

1

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

Перенаправление потоков

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

cat foo.txt | head

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

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

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

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

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

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

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

Когда 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).
  • Каталоги для других программ, чтобы размещать свои функции. Они находятся в каталогах, указанных в переменной среды XDG_DATA_DIRS, в подкаталоге fish/vendor_functions.d. По умолчанию обычно /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

Более подробную информацию см. в документации по встроенным командам или в разделе Условные выражения учебника.

Циклы и блоки

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

  • Подстановки, для создания имён файлов из шаблонов
  • Расширение переменных, для использования значения переменной
  • Подстановка команд, для использования вывода другой команды
  • Расширение фигурных скобок, для записи списков с общими префиксами или суффиксами более кратко
  • Расширение тильды, для преобразования ~ в начале путей в путь к домашнему каталогу

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

Подстановки

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

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

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

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

Примеры:

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

Для большинства команд, если какой-либо шаблон не удаётся расширить, команда не выполняется, $status устанавливается в ненулевое значение, и выводится предупреждение. Это поведение аналогично тому, что делает bash с shopt -s failglob. Существует ровно 4 исключения, а именно set, переопределение переменных в переопределениях, 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), команда innercommand выполняется первой. Её вывод используется, и каждая строка передаётся в качестве отдельного аргумента команде outercommand, которая затем выполняется. 4

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

Если вывод перенаправляется в команду string split или string split0 как последний шаг, эти разбиения используются как есть вместо разбиения строк.

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

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

Fish имеет ограничение по умолчанию в 100 Мбайт на данные, которые он будет считывать в подстановке команд. Если это ограничение достигнуто, команда (вся команда, а не только подстановка — внешняя команда не будет выполнена) терпит неудачу, и $status устанавливается в 122. Это сделано для того, чтобы подстановки команд не могли вызвать переполнение памяти системы, так как, как правило, ваша операционная система имеет гораздо более низкое ограничение, поэтому чтение большего объёма данных было бы бесполезным и вредным. Это ограничение может быть изменено с помощью переменной fish_read_limit (0 означает отсутствие ограничения). Это ограничение также влияет на команду read.

Примеры:

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

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

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

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

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

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

Примеры:

# 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

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

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

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

# 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. В частности, это необходимо для переменных, используемых для настройки внешних команд, таких как LESS или GOPATH, но также и для переменных, содержащих общие системные настройки, такие как PATH или LANGUAGE. Если внешней команде нужна переменная, она должна быть экспортирована.

Это также относится к рыбе - при запуске она получает переменные среды от своего родителя (обычно терминала). К ним обычно относятся системные настройки, такие как 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 в fish, а не с 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

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

Списки можно проверить с помощью команд count или contains:

count $smurf
# 2

contains blue $smurf
# key found, exits with 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"` .

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

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

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

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

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

> myfunction first second third
first
third

> myfunction apple cucumber banana
apple
banana

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

Более надежный подход к обработке аргументов — argparse, который проверяет определённые опции и помещает их в различные переменные, оставляя только позиционные аргументы в $argv. Вот простой пример:

function mybetterfunction
    argparse h/help s/second -- $argv
    or return # exit if argparse failed because it found an option it didn't recognize - it will print an error

    # If -h or --help is given, we print a little help text and return
    if set -q _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.
    if set -q _flag_second
        echo $argv[2]
    else
        echo $argv[1]
        echo $argv[3]
    end
end

Опции будут удалены из $argv, поэтому $argv[2] теперь является вторым позиционным аргументом:

> mybetterfunction first -s second third
second

Переменные PATH

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

Переменные PATH также будут экспортироваться в формате с двоеточиями, поэтому 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

Список директорий, в которых искать команды.

CDPATH

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

FISH_DEBUG

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

FISH_DEBUG_OUTPUT

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

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

Переменные локали 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_greeting

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

fish_history

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

fish_trace

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

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_pid

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

history

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

HOME

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

hostname

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

IFS

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

last_pid

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

PWD

текущий рабочий каталог.

pipestatus

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

SHLVL

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

status

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

status_generation

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

USER

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

version

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

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

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

Переменная status

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

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

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

  • 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, без инверсии.

END_OF_DOCUMENT_MARKER

Так что, если оба cat и grep завершились успешно, $status будет равно 1 из-за not, а $pipestatus будет равно 0 и 0.

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

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

LANG

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

LC_ALL

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

LC_COLLATE

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

LC_CTYPE

Устанавливает локаль для категории LC_CTYPE, которая определяет правила классификации, такие как тип символа (буква, цифра и т. д.).

LC_MESSAGES

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

LC_MONETARY

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

LC_NUMERIC

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

LC_TIME

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

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

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

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

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

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

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

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

  • Имя переменной не может быть пустым. Оно может содержать только буквы, цифры и символы подчёркивания. Оно может начинаться и заканчиваться любым из этих символов.
  • Имя функции не может быть пустым. Оно не может начинаться с дефиса («-») и не может содержать косую черту («/»). Все остальные символы, включая пробел, допустимы.
  • Имя режима привязки (например, 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 ищет каталоги в переменной среды XDG_DATA_DIRS для каталога fish/vendor_conf.d; если он не определён, по умолчанию используются /usr/share/fish/vendor_conf.d и /usr/local/share/fish/vendor_conf.d, если ваша дистрибуция не изменила это.

    Если в этих каталогах несколько файлов с одинаковым именем, выполнится только первый. Они выполняются в порядке их имён файлов, отсортированных (как в случае с шаблонами) в естественном порядке (например, «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           off 3.1 string replace -r needs fewer \\'s
ampersand-nobg-in-token off 3.4 & only backgrounds if followed by a separating character

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

  • stderr-nocaret был введён в fish 3.0 (и стал по умолчанию в 3.3). Он делает ^ обычным символом вместо обозначения перенаправления stderr, чтобы облегчить работу с цитированием и т. д. Используйте 2> вместо этого.
  • qmark-noglob также был введён в fish 3.0. Он делает ? обычным символом вместо одиночного символа шаблона. Используйте * вместо него (он будет соответствовать нескольким символам) или найдите другие способы сопоставления файлов, такие как find.
  • regex-easyesy был введён в 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,stderr-nocaret

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

> set -U fish_features stderr-nocaret qmark-noglob

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

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

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

set -Ua fish_features no-stderr-nocaret

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

  • stderr-nocaret - ^ больше не перенаправляет stderr, используйте 2>. Включено по умолчанию в fish 3.3.0.

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

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

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

Пример:

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

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

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

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

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

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

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

© 2022 fish-shell developers
Licensed under the GNU General Public License, version 2.
https://fishshell.com/docs/3.4/language.html

Spec-Zone.ru

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