Язык оболочки 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: Отобразить содержимое файлов
Команды и аргументы разделяются пробелом ' '. Каждая команда завершается либо новой строкой (нажатием клавиши Enter), либо точкой с запятой ;. Несколько команд можно записать в одной строке, разделив их точками с запятой.
Переключатель — очень распространённый специальный тип аргумента. Переключатели почти всегда начинаются с одного или нескольких дефисов - и изменяют способ работы команды. Например, команда 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— буква алфавита, представляет управляющую последовательность, генерируемую нажатием клавиши Control и указанной буквы. Например,\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для отключения вывода, записывая его в специальный «сток». - Знак амперсанда (
&) за которым следует номер другого дескриптора файла, например&2для стандартной ошибки. Вывод будет записан в указанный дескриптор. - Амперсанд, за которым следует знак минуса (
&-). Дескриптор файла будет закрыт.
Для удобства перенаправление &> может использоваться для перенаправления как stdout, так и stderr в одно и то же место назначения. Например, echo hello &> all_output.txt перенаправляет и stdout, и stderr в файл all_output.txt. Это эквивалентно echo hello > all_output.txt 2>&1.
Любой произвольный дескриптор файла может быть использован в перенаправлении, предварив перенаправление номером FD.
- Для перенаправления ввода дескриптора N используйте
N<DESTINATION. - Для перенаправления вывода дескриптора N используйте
N>DESTINATION. - Для добавления вывода дескриптора N в файл используйте
N>>DESTINATION_FILE.
Например, echo hello 2> output.stderr записывает стандартную ошибку (дескриптор файла 2) в output.stderr.
Перенаправление встроенных функций или блоков на дескриптор файла выше 2 является ошибкой. Однако это поддерживается для внешних команд.
-
1 -
Предыдущие версии fish также позволяли указать это как
^DESTINATION, но это делало другой символ специальным, поэтому он был устаревшим и удалён. См. Флаги функций.
Перенаправление через трубу
Другой способ перенаправить потоки — использовать трубу. Труба соединяет потоки друг с другом. Обычно стандартный вывод одной команды соединяется со стандартным вводом другой. Это делается путём разделения команд символом трубы |. Например:
cat foo.txt | head
Команда cat foo.txt отправляет содержимое foo.txt в stdout. Этот вывод используется в качестве ввода для программы head, которая выводит первые 10 строк своего ввода.
Возможна передача другого дескриптора вывода, добавив его номер FD и символ перенаправления вывода к трубе. Например:
make fish 2>| less
попытается выполнить fish, и любые ошибки будут отображены с помощью программы less. 2
Для удобства труба &| перенаправляет как stdout, так и stderr в один и тот же процесс. Это отличается от bash, который использует |&.
-
2 -
Здесь «программа вывода» — это программа, которая принимает вывод и «странирует» его.
lessне только страницует, но и позволяет произвольное прокручивание (даже назад!).
Управление задачами
Когда вы запускаете задачу в fish, сам fish приостанавливается и передаёт управление терминалом только что запущенной программе. Иногда вы хотите продолжать использовать командную строку и запустить задачу в фоновом режиме. Чтобы создать фоновую задачу, добавьте к вашей команде & (амперсанд). Это укажет fish на запуск задачи в фоновом режиме. Фоновые задачи очень полезны при запуске программ с графическим интерфейсом.
Пример:
emacs &
запустит текстовый редактор emacs в фоновом режиме. fg может быть использован для возвращения его в фоновый режим, когда это потребуется.
Большинство программ позволяют приостановить выполнение программы и вернуть управление fish, нажав Control+Z (также обозначается как ^Z). Вернувшись в командную строку fish, вы можете запустить другие программы и сделать всё, что вам нужно. Если затем вы хотите вернуться к приостановленной команде, используйте команду fg (фоновый режим).
Если вы хотите поместить приостановленную задачу в фоновый режим, используйте команду bg.
Чтобы получить список всех запущенных задач, используйте команду jobs. Эти задачи можно удалить с помощью команды disown.
В данный момент функции не могут быть запущены в фоновом режиме. Функции, которые останавливаются и затем перезапускаются в фоновом режиме с помощью команды bg, не будут выполняться корректно.
Если символ & следует за неразделяющим символом, он не интерпретируется как оператор фонового режима. Разделяющими символами являются пробелы и символы ;<>&|.
Функции
Функции представляют собой программы, написанные на языке синтаксиса fish. Они группируют различные команды и их аргументы под одним именем.
Например, вот простая функция для отображения содержимого каталогов:
function ll
ls -l $argv
end
Первая строка указывает fish определить функцию с именем ll, чтобы её можно было использовать, просто написав ll в командной строке. Вторая строка указывает fish, что команда ls -l $argv должна быть вызвана, когда вызвана ll. $argv — это переменная списка, которая всегда содержит все аргументы, переданные функции. В приведённом примере эти аргументы просто передаются команде ls. Строка end завершает определение.
Вызов этой функции как ll /tmp/ приведет к выполнению ls -l /tmp/, что отобразит содержимое /tmp.
Это своего рода функция, известная как обёртка или «псевдоним».
Подсказка fish также определена в функции, называемой fish_prompt. Она выполняется перед отображением подсказки, и её вывод формирует подсказку:
function fish_prompt
# A simple prompt. Displays the current directory
# (which fish stores in the $PWD variable)
# and then a user symbol - a '►' for a normal user and a '#' for root.
set -l user_char '►'
if fish_is_root_user
set user_char '#'
end
echo (set_color yellow)$PWD (set_color purple)$user_char
end
Для редактирования функции можно использовать funced, а для сохранения функции — funcsave. Это позволит сохранить её в файле функции, который fish будет автозагружать при необходимости.
Встроенная команда functions может показать текущее определение функции (и команда type также может это сделать, если ей передать имя функции).
Дополнительную информацию о функциях можно найти в документации по встроенной команде function.
Определение псевдонимов
Одно из наиболее распространённых применений функций — небольшое изменение поведения уже существующей команды. Например, можно переопределить команду ls для отображения цветов. Переключатель для включения цветов в системах GNU — --color=auto. Псевдоним, или обёртка, вокруг команды ls может выглядеть так:
function ls
command ls --color=auto $argv
end
Необходимо обратить внимание на несколько важных моментов, касающихся псевдонимов:
- Всегда добавляйте переменную $argv в список параметров обернутой команды. Это гарантирует, что если пользователь предоставит дополнительные параметры функции, они будут переданы подчинённой команде.
- Если псевдоним имеет то же имя, что и обозначаемая им команда, необходимо добавить префикс
commandк вызову программы, чтобы указать fish, что функция не должна вызывать саму себя, а должна вызывать команду с таким же именем. Если это будет пропущено, функция будет вызывать себя до бесконечности. Обычно fish достаточно умён, чтобы это распознать и воздержаться от этого (что, надеюсь, в ваших интересах).
Для лёгкого создания функций такого типа можно использовать команду alias. В отличие от других оболочек, она просто создаёт функции — в fish нет отдельного понятия «псевдонима», мы просто используем это слово для функций-обёрток такого типа. Команда alias немедленно создаёт функцию. Рассмотрите возможность использования alias --save или funcsave, чтобы сохранить созданную функцию в файле автозагрузки, вместо того чтобы каждый раз создавать псевдоним.
В качестве альтернативы попробуйте использовать сокращения. Это слова, которые расширяются по мере ввода, а не являются фактическими функциями внутри оболочки.
Автозагрузка функций
Функции могут быть определены в командной строке или в файле конфигурации, но они также могут быть загружены автоматически. Это имеет некоторые преимущества:
- Автоматически загружаемая функция становится доступной для всех работающих оболочек.
- Если определение функции изменено, все работающие оболочки автоматически перезагрузят изменённую версию по истечении некоторого времени.
- Улучшается время запуска и использование памяти и т.д.
При необходимости загрузки функции fish ищет в каталогах в переменной списка $fish_function_path файлы с именем, состоящим из имени функции плюс суффикс .fish, и загружает первый найденный.
Например, если вы попытаетесь выполнить что-то под названием banana, fish пройдёт по всем каталогам в $fish_function_path, ища файл под названием banana.fish и загрузит первый найденный.
По умолчанию $fish_function_path содержит следующее:
- Каталог для пользователей для хранения своих функций, обычно
~/.config/fish/functions(управляемый переменной окруженияXDG_CONFIG_HOME). - Каталог для функций для всех пользователей системы, обычно
/etc/fish/functions(на самом деле$__fish_sysconfdir/functions). - Каталоги для другого программного обеспечения для размещения собственных функций. Они находятся в каталогах в
$__fish_user_data_dir(обычно~/.local/share/fish, контролируемый переменной окруженияXDG_DATA_HOME) и в переменной окруженияXDG_DATA_DIRS, в подкаталогеfish/vendor_functions.d. Значение по умолчанию дляXDG_DATA_DIRSобычно/usr/share/fish/vendor_functions.dи/usr/local/share/fish/vendor_functions.d. - Функции, поставляемые с fish, обычно установленные в
/usr/share/fish/functions(на самом деле$__fish_data_dir/functions).
Если вы не уверены, ваши функции, вероятно, находятся в ~/.config/fish/functions.
Как уже объяснялось, файлы автозагрузки загружаются по имени, поэтому, хотя вы можете поместить несколько функций в один файл, файл будет загружаться автоматически только после попытки выполнить функцию с тем же именем.
Автозагрузка также не будет работать для обработчиков событий, поскольку fish не может знать, что функция должна быть выполнена при возникновении события, когда она ещё не загружена. Для получения дополнительной информации см. раздел обработчики событий.
Если файл с соответствующим именем не определяет функцию, fish не будет читать другие файлы автозагрузки, а продолжит попытку использовать встроенные команды и, наконец, команды. Это позволяет маскировать функции, определённые позже в $fish_function_path, например, если ваш администратор поместил что-то в /etc/fish/functions, что вы хотите пропустить.
Если вы разрабатываете другую программу и хотите установить функции fish для неё, установите их в каталог функций «vendor». Поскольку этот путь различается в разных системах, вы можете использовать pkgconfig для определения его с помощью вывода pkg-config --variable functionsdir fish. Ваша система установки должна поддерживать пользовательский путь для переопределения пути pkgconfig, так как другим дистрибутивам может потребоваться легко его изменить.
Условные операторы
Fish имеет некоторые встроенные команды, позволяющие выполнять команды только при выполнении определённого критерия: 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 . Есть исключения, а именно set и path, которые переопределяют переменные в переопределениях, count и for. Их подстановки будут расширяться до нуля аргументов (так что команда их вообще не увидит), как с shopt -s nullglob в bash.
Примеры:
# List the .foo files, or warns if there aren't any.
ls *.foo
# List the .foo files, if any.
set foos *.foo
if count $foos >/dev/null
ls $foos
end
В отличие от bash (по умолчанию), fish не передаст буквальный символ подстановки, если соответствий не найдено. Поэтому для команды, такой как apt install, которая сама выполняет подстановку, вам нужно добавить кавычки:
apt install "ncurses-*"
Расширение переменных
Одним из самых важных расширений в fish является «расширение переменных». Это замена знака доллара ($) за которым следует имя переменной на _значение_ этой переменной. Подробнее о переменных оболочки см. раздел Переменные оболочки.
В самом простом случае это выглядит так:
echo $HOME
что заменит $HOME на домашний каталог текущего пользователя и передаст его команде echo, которая затем выведет его.
Некоторые переменные, такие как $HOME, уже установлены, потому что fish устанавливает их по умолчанию или потому что родительский процесс fish передал их fish при его запуске. Вы можете определить свои собственные переменные, установив их с помощью set:
set my_directory /home/cooluser/mystuff ls $my_directory # shows the contents of /home/cooluser/mystuff
Подробнее о том, как работают установки переменных, см. Переменные оболочки и следующие разделы.
Иногда у переменной нет значения, потому что она не определена или пустая, и она расширяется до ничего:
echo $nonexistentvariable # Prints no output.
Чтобы отделить имя переменной от текста, можно заключить переменную в двойные кавычки или фигурные скобки:
set WORD cat
echo The plural of $WORD is "$WORD"s
# Prints "The plural of cat is cats" because $WORD is set to "cat".
echo The plural of $WORD is {$WORD}s
# ditto
Без кавычек или фигурных скобок fish попытается расширить переменную с именем $WORDs, которая может не существовать.
Последний синтаксис {$WORD} — это частный случай расширения фигурных скобок.
Если $WORD не определена или является пустым списком, «s» не выводится. Однако он выводится, если $WORD — пустая строка (например, после set WORD "").
Цитата переменных
В отличие от всех других расширений, расширение переменных также происходит в строках с двойными кавычками. Внутри двойных кавычек ("these") переменные всегда расширяются ровно до одного аргумента. Если они пустые или не определены, это приведет к пустой строке. Если они содержат один элемент, они будут расширяться до этого элемента. Если их больше, элементы будут объединены пробелами, если переменная не является переменной пути — в этом случае будет использоваться двоеточие (:) вместо 3.
За пределами двойных кавычек переменные будут расширяться до столько аргументов, сколько у них элементов. Это означает, что пустой список будет расширяться до ничего, переменная с одним элементом будет расширяться до этого элемента, а переменная с несколькими элементами будет расширяться до каждого из этих элементов по отдельности.
Если переменная расширяется до ничего, она аннулирует любые другие строки, прикрепленные к ней. Более подробную информацию см. в разделе декартово произведение.
В отличие от других оболочек, fish не выполняет «разделение слов». После того, как переменная установлена в определённый набор элементов, эти элементы расширяются сами по себе. Они не разделены пробелами или символами новой строки или чем-либо ещё:
> set foo one\nthing > echo $foo one thing > printf '|%s|\n' $foo |one thing|
Это означает, что кавычки не являются абсолютной необходимостью, как в других оболочках. В большинстве случаев не использование кавычек верно. Исключение составляет случай, когда нужно гарантировать, что переменная передаётся как один элемент, даже если она может быть не установлена или содержать несколько элементов. Это часто встречается в команде test:
set -l foo one two three test -n $foo # prints an error that it got too many arguments, because it was executed like test -n one two three test -n "$foo" # works, because it was executed like test -n "one two three"
-
3 -
В отличие от bash или zsh, которые объединяют символом первого символа $IFS (который обычно является пробелом).
Разрешение переменных
Символ $ также может использоваться несколько раз в качестве оператора «разрешения» (аналога * в C или C++), как в следующем коде:
set foo a b c
set a 10; set b 20; set c 30
for i in (seq (count $$foo))
echo $$foo[$i]
end
# Output is:
# 10
# 20
# 30
$$foo[$i] — «значение переменной, имя которой $foo[$i]».
При использовании этой функции вместе с квадратными скобками квадратные скобки будут использоваться изнутри наружу. $$foo[5] будет использовать пятый элемент $foo в качестве имени переменной, а не пятый элемент всех переменных, к которым ссылается $foo. Это вместо этого выражается как $$foo[1..-1][5] (возьмите все элементы $foo, используйте их как имена переменных, а затем возьмите пятый элемент этих переменных).
Подстановка команд
Выход команды (или целой последовательности команд) может быть использован в качестве аргументов другой команды.
Когда вы пишете команду в скобках, например outercommand (innercommand), то innercommand будет выполнена первой. Её вывод будет взят, и каждая строка будет задана в качестве отдельного аргумента для outercommand, который затем будет выполнен. 4
Подстановка команды может иметь знак доллара перед открывающей скобкой, например outercommand $(innercommand). Этот вариант также разрешён внутри двойных кавычек. При использовании двойных кавычек вывод команды не разбивается по строкам.
Если вывод перенаправлен в разбиение строки или разбиение строки0 как последний шаг, эти разбиения используются как есть, вместо разделения строк.
Код завершения последней выполненной подстановки команды доступен в переменной статус, если подстановка происходит в контексте команды 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в пустое значение отключит разделение по строкам. Это устарело, используйте разбиение строки вместо этого.
Расширение фигурных скобок
Фигурные скобки могут использоваться для записи списков, разделённых запятыми. Они будут расширены, и каждый элемент станет новым параметром, с прикреплённой окружающей строкой. Это полезно для экономии набора текста и для отделения имени переменной от окружающего текста.
Примеры:
> 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
В случае сомнений, используйте переменные со сферой действия функций. Когда вам нужно сделать переменную доступной везде, сделайте её глобальной. Когда вам нужно постоянно хранить конфигурацию, сделайте её универсальной. Когда вы хотите использовать переменную только в небольшом блоке, сделайте её локальной.
Переопределение переменных для одной команды
Если вы хотите переопределить переменную для одной команды, вы можете использовать операторы «var=val» перед командой:
# Call git status on another directory # (can also be done via `git -C somerepo status`) GIT_DIR=somerepo git status
В отличие от других оболочек, fish сначала установит переменную, а затем выполнит другие расширения в строке, поэтому:
set foo banana foo=gagaga echo $foo # prints gagaga, while in other shells it might print "banana"
Несколько элементов можно указать в расширении фигурных скобок:
# Call bash with a reasonable default path.
PATH={/usr,}/{s,}bin bash
Или с шаблоном:
# Run vlc on all mp3 files in the current directory # If no file exists it will still be run with no arguments mp3s=*.mp3 vlc $mp3s
В отличие от других оболочек, это не запрещает какой-либо поиск (псевдонимы и т. п.). Вызов команды после установки переопределения переменной приведёт к запуску той же самой команды.
Этот синтаксис поддерживается с версии fish 3.1.
Подробнее об универсальных переменных
Универсальные переменные — это переменные, которые общие для всех сеансов fish пользователя на компьютере. Fish хранит многие свои параметры конфигурации в виде универсальных переменных. Это означает, что для изменения настроек fish вам нужно изменить значение переменной один раз, и оно будет автоматически обновлено для всех сеансов и сохранено после перезагрузки компьютера и входа/выхода.
Чтобы увидеть универсальные переменные в действии, запустите два сеанса fish рядом и выполните следующую команду в одном из них set fish_color_cwd blue. Поскольку fish_color_cwd — универсальная переменная, цвет текущей рабочей директории в подсказке мгновенно изменится на синий в обоих терминалах.
Универсальные переменные хранятся в файле .config/fish/fish_variables. Не редактируйте этот файл напрямую, так как ваши изменения могут быть перезаписаны. Редактируйте переменные через скрипты fish или с помощью интерактивной оболочки fish.
Не добавляйте в универсальные переменные в config.fish, потому что эти переменные будут удлиняться с каждым новым экземпляром оболочки. Вместо этого просто установите их один раз в командной строке.
Область действия переменных для функций
При вызове функции все текущие локальные переменные временно исчезают. Это затемнение локальной области действия необходимо, поскольку пространство имён переменных станет переполненным, что сильно затруднит случайное переопределение переменных из другой функции.
Например:
function shiver
set phrase 'Shiver me timbers'
end
function avast
set --local phrase 'Avast, mateys'
# Calling the shiver function here can not
# change any variables in the local scope
shiver
echo $phrase
end
avast
# Outputs "Avast, mateys"
Экспорт переменных
Переменные в fish могут быть «экспортированы», поэтому они будут унаследованы любыми командами, запущенными fish. В частности, это необходимо для переменных, используемых для настройки внешних команд, таких как LESS или GOPATH, а также для переменных, содержащих общие системные настройки, такие как PATH или LANGUAGE. Если внешняя команда должна знать переменную, она должна быть экспортирована.
Это также относится к fish — при запуске она получает переменные окружения от своего родительского процесса (обычно терминала). Они обычно включают системную конфигурацию, такую как PATH и переменные локали.
Переменные могут быть явно установлены как экспортируемые с помощью переключателя -x или --export, или неэкспортируемые с помощью переключателя -u или --unexport. Правила экспорта при установке переменной идентичны правилам области видимости для переменных:
- Если переменная явно установлена как экспортируемая или неэкспортируемая, это значение будет сохранено.
- Если переменная не явно установлена как экспортируемая или неэкспортируемая, но была ранее определена, предыдущее правило экспорта для переменной сохраняется.
- В противном случае, по умолчанию, переменная не будет экспортирована.
- Если переменная имеет область действия функции или локальную область действия и экспортирована, любая вызванная функция получает её копию, поэтому любые изменения, которые она вносит в переменную, исчезают по возвращении из функции.
- Глобальные переменные доступны функциям, независимо от того, экспортированы они или нет.
В качестве соглашения об именовании экспортированные переменные записываются заглавными буквами, а неэкспортированные — строчными.
Например:
set -gx ANDROID_HOME ~/.android # /opt/android-sdk set -gx CDPATH . ~ (test -e ~/Videos; and echo ~/Videos) set -gx EDITOR emacs -nw set -gx GOPATH ~/dev/go set -gx GTK2_RC_FILES "$XDG_CONFIG_HOME/gtk-2.0/gtkrc" set -gx LESSHISTFILE "-"
Примечание: Экспорт — это не область действия, а дополнительное состояние. Обычно имеет смысл сделать экспортированные переменные глобальными, но локально экспортированные переменные могут быть полезны, если вам нужно что-то более конкретное, чем Переопределения. Они копируются в функции, поэтому функция не может изменить их вне функции, и они по-прежнему доступны командам.
Списки
Fish может хранить список (или «массив», если хотите) нескольких строк внутри переменной:
> set mylist first second third > printf '%s\n' $mylist # prints each element on its own line first second third
Чтобы получить доступ к одному элементу списка, используйте его индекс в квадратных скобках, например:
echo $PATH[3]
Индексы списков в fish начинаются с 1, а не с 0, как в других языках. Это потому, что это требует меньше вычитаний 1, и многие распространённые утилиты Unix, такие как seq работают лучше с этим (seq 5 выводит 1 до 5, а не 0 до 5). Неверный индекс игнорируется без сообщений об ошибке, что приводит к отсутствию значения (даже не пустой строки, а просто отсутствию аргумента).
Если вы не используете квадратные скобки, все элементы списка будут переданы команде как отдельные элементы. Это означает, что вы можете перебирать список с помощью for:
for i in $PATH
echo $i is in the path
end
Это перебирает каждый каталог в PATH по отдельности и выводит строку, указывающую, что он находится в пути.
Чтобы создать переменную smurf, содержащую элементы blue и small, просто напишите:
set smurf blue small
Также можно устанавливать или удалять отдельные элементы списка:
# Set smurf to be a list with the elements 'blue' and 'small' set smurf blue small # Change the second element of smurf to 'evil' set smurf[2] evil # Erase the first element set -e smurf[1] # Output 'evil' echo $smurf
Если вы указываете отрицательный индекс при расширении или присваивании переменной списка, индекс будет взят с конца списка. Например, индекс -1 — это последний элемент списка:
> set fruit apple orange banana > echo $fruit[-1] banana > echo $fruit[-2..-1] orange banana > echo $fruit[-1..1] # reverses the list banana orange apple
Как видите, вы можете использовать диапазон индексов, см. диапазон индексов для получения подробностей.
Все списки одномерные и не могут содержать другие списки, хотя можно имитировать вложенные списки с помощью косвенного обращения — см. расширение переменных.
Когда список экспортируется как переменная окружения, он разделяется пробелами или двоеточиями, в зависимости от того, является ли он переменной пути:
> set -x smurf blue small > set -x smurf_PATH forest mushroom > env | grep smurf smurf=blue small smurf_PATH=forest:mushroom
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 -
текущее имя пользователя. Эту переменную можно изменить.
-
EUID -
текущий эффективный идентификатор пользователя, устанавливается fish при запуске. Эту переменную можно изменить.
-
version -
версия работающей в данный момент fish (также доступна как
FISH_VERSIONдля обратной совместимости).
По соглашению, для экспортируемых переменных обычно используется имя с заглавными буквами, а переменные со строчными буквами не экспортируются. (CMD_DURATION — исключение по историческим причинам). Это правило не навязывается fish, но хорошая практика — использовать регистр для различения экспортируемых и неэкспортируемых переменных.
Fish также использует некоторые переменные внутри, их имена обычно начинаются с __fish. Они являются внутренними и обычно не должны изменяться напрямую.
Переменная состояния
Всякий раз, когда процесс завершается, состояние завершения возвращается программе, которая его запустила (обычно оболочке). Это состояние завершения — целое число, которое сообщает вызывающему приложению, как прошла обработка команды. В целом, нулевое состояние завершения означает, что команда выполнилась без проблем, а ненулевое — что возникла проблема.
Fish хранит состояние завершения последнего процесса в последней задаче, которая завершилась, в переменной status.
Если fish сталкивается с проблемой при выполнении команды, переменная состояния также может быть установлена в определённое значение:
- 0 обычно является состоянием завершения команд, если они успешно выполнили запрошенную операцию.
- 1 обычно является состоянием завершения команд, если они не смогли выполнить запрошенную операцию.
- 121 обычно является состоянием завершения команд, если им были переданы некорректные аргументы.
- 123 означает, что команда не была выполнена, потому что имя команды содержало недопустимые символы.
- 124 означает, что команда не была выполнена, потому что ни один из подстановочных знаков в команде не дал совпадений.
- 125 означает, что хотя исполняемый файл с указанным именем был найден, операционная система не смогла выполнить команду.
- 126 означает, что хотя файл с указанным именем был найден, он не был исполняемым.
- 127 означает, что ни функция, ни встроенная команда, ни команда с данным именем не были найдены.
Если процесс завершается по сигналу, состояние завершения будет равно 128 плюс номер сигнала.
Состояние можно инвертировать с помощью not (или !), что полезно в условии. Это преобразует состояние 0 в 1 и любое ненулевое состояние в 0.
Также есть $pipestatus, который представляет собой список всех status значений процессов в конвейере. Разница заключается в том, что not применяется к $status, но не к $pipestatus, потому что теряет информацию.
Например:
not cat file | grep -q fish echo status is: $status pipestatus is $pipestatus
Здесь $status отражает состояние grep, которое возвращает 0, если найдено что-то, инвертированное с помощью not (то есть 1, если что-то найдено, 0 в противном случае). $pipestatus отражает состояние cat (которое возвращает ненулевое значение, например, когда файл не найден) и grep, без инверсии.
Таким образом, если оба cat и grep завершились успешно, $status будет равно 1 из-за not, а $pipestatus будет равно 0 и 0.
Переменные локали
«Локаль» программы — это набор языковых и региональных параметров, зависящих от языка и культурных обычаев. В 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 ищет каталоги в
$__fish_user_data_dir(обычно~/.local/share/fish, управляемый переменной окруженияXDG_DATA_HOME) и в переменной окруженияXDG_DATA_DIRSдля каталогаfish/vendor_conf.d; если не определено, по умолчаниюXDG_DATA_DIRS— это/usr/share/fish/vendor_conf.dи/usr/local/share/fish/vendor_conf.d, если ваша дистрибуция не изменила это.
Если в этих каталогах есть несколько файлов с одинаковым именем, будет выполнен только первый. Они выполняются в порядке их имени файла, отсортированного (как в шаблонах) в естественном порядке (например, «01» сортируется раньше «2»).
-
- Системные файлы конфигурации, где администраторы могут включить инициализацию для всех пользователей в системе — подобно
/etc/profileдля оболочек в стиле POSIX — в$__fish_sysconf_dir(обычно/etc/fish/config.fish). - Конфигурация пользователя, обычно в
~/.config/fish/config.fish(управляемая переменной окруженияXDG_CONFIG_HOME, и доступна как$__fish_config_dir).
~/.config/fish/config.fish подключается после фрагментов. Это делается для того, чтобы вы могли копировать фрагменты и переопределять некоторые их поведения.
Все эти файлы выполняются при запуске каждой оболочки. Если вы хотите запустить команду только при запуске интерактивной оболочки, используйте код возврата команды status --is-interactive для определения, является ли оболочка интерактивной. Если вы хотите запустить команду только при использовании логиновой оболочки, используйте status --is-login вместо этого. Это ускорит запуск неинтерактивных или нелогиновых оболочек.
Если вы разрабатываете другую программу, вы можете захотеть добавить конфигурацию для всех пользователей fish в системе. Это не рекомендуется; если не написано тщательно, это может иметь побочные эффекты или замедлить запуск оболочки. Кроме того, пользователи других оболочек не получат выгоды от специфичной для fish конфигурации. Однако, если это необходимо, вы можете установить их в каталог конфигурации «vendor». Поскольку этот путь может различаться в зависимости от системы, для определения его следует использовать pkg-config: pkg-config --variable confdir fish.
Будущие флаги функций
Флаги функций — это способ, которым fish подготавливает изменения, которые могут сломать скрипты. Разрушающие изменения вводятся как опциональные, через несколько релизов они становятся исключительной опцией, а затем старое поведение удаляется.
Вы можете увидеть текущий список функций через status features:
> status features stderr-nocaret on 3.0 ^ no longer redirects stderr qmark-noglob off 3.0 ? no longer globs regex-easyesc on 3.1 string replace -r needs fewer \\'s ampersand-nobg-in-token on 3.4 & only backgrounds if followed by a separating character
Вот что они означают:
-
stderr-nocaretбыл введён в fish 3.0 (и стал по умолчанию в 3.3). Он делает^обычным символом вместо обозначения перенаправления stderr, чтобы упростить работу с цитированием и т.п. Используйте2>вместо этого. С fish 3.5 это больше нельзя отключать. Флаг по-прежнему можно проверять на совместимость, но значениеno-stderr-nocaretпросто будет проигнорировано. -
qmark-noglobтакже был введён в fish 3.0. Он делает?обычным символом вместо одиночного символа glob. Используйте*вместо (что будет соответствовать нескольким символам) или найдите другие способы сопоставления файлов, такие какfind. -
regex-easyescбыл введён в 3.1. Он делает так, что выражение подстановки вstring replace -rвыполняет на одну итерацию меньше экранирования. Раньше, чтобы экранировать обратную косую черту, нужно было использоватьstring replace -ra '([ab])' '\\\\\\\\$1'. Теперь достаточно'\\\\$1'. Проверьте ваши вызовыstring replace, если вы используете это где-либо. -
ampersand-nobg-in-tokenбыл введён в fish 3.4. Он делает так, что&больше не интерпретируется как оператор фонового выполнения в середине токена, что упрощает работу с URL-адресами. Поставьте пробелы или точку с запятой после&. Такое форматирование всё равно рекомендуется, иfish_indentуже сделает это за вас.
Эти изменения включены по умолчанию. Их можно включить на сессию:
> fish --features qmark-noglob,regex-easyesc
или включить глобально для пользователя:
> set -U fish_features regex-easyesc qmark-noglob
Функции будут установлены только при запуске, поэтому эта переменная будет действовать только если она универсальна или экспортирована.
Вы также можете использовать версию как группу, поэтому 3.0 эквивалентно «stderr-nocaret» и «qmark-noglob». Вместо версии специальная группа all включает все функции.
Добавление префикса no- к функции отключает её. Например, чтобы снова включить ? одиночного символа glob:
set -Ua fish_features no-qmark-noglob
В настоящее время по умолчанию включены следующие функции:
- stderr-nocaret —
^больше не перенаправляет stderr, используйте2>. Включено по умолчанию в fish 3.3.0. Больше нельзя изменять с fish 3.5.0. - regex-easyesc —
string replace -rтребует меньше обратных косых черт в части подстановки. Включено по умолчанию в fish 3.5.0. - ampersand-nobg-in-token —
&в середине слова является обычным символом вместо фонового выполнения. Включено по умолчанию в fish 3.5.0.
Обработчики событий
При определении новой функции в fish, её можно сделать обработчиком событий, т.е. функцией, которая автоматически выполняется при наступлении определённого события. События, которые могут вызвать обработчик, — это:
- Когда посылается сигнал
- Когда завершается работа задачи
- Когда значение переменной обновляется
- Когда скоро будет показан приглашающий знак
Пример:
Для определения обработчика сигналов для сигнала WINCH напишите:
function my_signal_handler --on-signal WINCH
echo Got WINCH signal!
end
Обратите внимание, что обработчики событий становятся активными только при загрузке функции, поэтому вам необходимо иначе подключить или выполнить функцию вместо того, чтобы полагаться на автозагрузку. Один из подходов — поместить его в ваш файл конфигурации.
Дополнительную информацию об определении новых обработчиков событий см. в документации для команды 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.5/language.html
Комментарии
Всё, что следует за
#до конца строки, является комментарием. Это означает, что он предназначен только для удобства чтения, 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Многострочных комментариев нет. Если вам нужно создать комментарий, занимающий несколько строк, просто начните каждую строку с
#.Комментарии также могут появляться после строки, как показано ниже: