Язык командной оболочки 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») и каталоги в домашней директории.
Для большинства команд, если какой-либо шаблон не удаётся расширить, команда не выполняется, $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, без инверсии.
Так что, если оба 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