Язык fish
Этот документ представляет собой всеобъемлющий обзор скриптового языка fish.
Для интерактивных функций см. Интерактивное использование.
Обзор синтаксиса
Оболочки, подобные fish, используются для выполнения команд. Команда выполняется путем написания имени команды, за которым следуют любые аргументы. Например:
echo hello world
echo команда выводит свои аргументы на экран. В этом примере вывод — hello world.
Все в fish выполняется с помощью команд. Существуют команды для повторения других команд, команды для присвоения переменных, команды для обработки группы команд как единой команды и т. д. Все эти команды следуют одному базовому синтаксису.
Любой программе на вашем компьютере можно использовать как команду в fish. Если файл программы находится в одном из каталогов PATH, вы можете просто ввести имя программы, чтобы использовать ее. В противном случае требуется полное имя файла, включая каталог (например, /home/me/code/checkers/checkers или ../checkers).
Вот список некоторых полезных команд:
- cd: Изменение текущего каталога
-
ls: Список файлов и каталогов -
man: Отображение страницы справки — попробуйтеman ls, чтобы получить помощь по команде «ls», илиman mv, чтобы получить информацию о команде «mv». -
mv: Перемещение (переименование) файлов -
cp: Копирование файлов - open: Открытие файлов с помощью приложения по умолчанию, связанного с типом каждого файла
-
less: Отображение содержимого файлов
Команды и аргументы разделяются символом пробела ' '. Каждая команда завершается либо новой строкой (нажатием клавиши возврата) либо точкой с запятой ;. Несколько команд можно записать в одной строке, разделив их точками с запятой.
Переключатель — это очень распространенный специальный тип аргумента. Переключатели почти всегда начинаются с одного или нескольких тире - и изменяют способ работы команды. Например, команда ls обычно выводит имена всех файлов и каталогов в текущем рабочем каталоге. Используя переключатель -l, поведение ls изменяется таким образом, что отображаются не только имена файлов, но и размер, права доступа, владелец и время изменения каждого файла.
Переключатели различаются между командами и обычно документируются в справочной странице команды. Однако существуют некоторые переключатели, общие для большинства команд. Например, --help обычно отображает текст справки, --version обычно отображает версию команды, а -i часто включает интерактивное запроса перед выполнением действия. Попробуйте man your-command-here, чтобы получить информацию о переключателях вашей команды.
Таким образом, основная идея fish такая же, как и в других оболочках Unix: она получает командную строку, выполняет расширения, а результат затем выполняется как команда.
Терминология
Здесь мы определяем некоторые термины, используемые на этой странице и в остальной части документации fish:
-
Аргумент: Параметр, задаваемый команде. В
echo foo, «foo» является аргументом. -
Встроенная команда: Команда, реализованная оболочкой. Встроенные команды так тесно связаны с работой оболочки, что их невозможно реализовать как внешние команды. В
echo foo, «echo» является встроенной командой. -
Команда: Программа, которую может запустить оболочка, или, точнее, внешняя программа, которую оболочка запускает в другом процессе. Внешние команды предоставляются вашей системой в виде исполняемых файлов. В
echo foo«echo» — встроенная команда, вcommand echo foo«echo» — внешняя команда, предоставляемая файлом, например, /bin/echo. - Функция: Блок команд, которые можно вызывать как одну команду. Используя функции, можно объединить несколько простых команд в одну более сложную команду.
- Задача: Запущенная командная цепочка или команда.
-
Командная цепочка: Набор команд, объединенных так, что выход одной команды является входом следующей команды.
echo foo | grep foo— это командная цепочка. - Перенаправление: Операция, изменяющая один из потоков ввода или вывода, связанных с задачей.
-
Переключатель или Вариант: Специальный вид аргумента, изменяющий поведение команды. Переключатель почти всегда начинается с одного или двух тире. В
echo -n foo«-n» — это вариант.
Кавычки
Иногда вы хотите передать команде аргумент, содержащий символы, имеющие специальное значение для fish, например пробелы или $ или *. Для этого можно использовать кавычки:
rm "my file.txt"
чтобы удалить файл с именем my file.txt вместо того, чтобы пытаться удалить два файла my и file.txt.
Fish понимает два типа кавычек: одинарные (') и двойные ("), и они работают немного по-разному.
В одинарных кавычках fish не выполняет никаких расширений. В двойных кавычках fish выполняет только расширение переменных и подстановку команд в $(command). Никакие другие виды расширений (включая расширение фигурных скобок или расширение параметров) не выполняются, и управляющие последовательности (например, \n) игнорируются. В кавычках пробелы не используются для разделения аргументов, что позволяет аргументам в кавычках содержать пробелы.
Единственными значимыми управляющими последовательностями в одинарных кавычках являются \', которая экранирует одинарную кавычку, и \\, которая экранирует символ обратного слэша. Единственными значимыми управляющими последовательностями в двойных кавычках являются \", которая экранирует двойную кавычку, \$, которая экранирует символ доллара, \ , за которым следует новая строка, что удаляет обратный слэш и новую строку, и \\, которая экранирует символ обратного слэша.
Одинарные кавычки не имеют специального значения внутри двойных кавычек, и наоборот.
Дополнительные примеры:
grep 'enabled)$' foo.txt
ищет строки, оканчивающиеся на enabled) в foo.txt (символ $ является специальным для grep: он соответствует концу строки).
apt install "postgres-*"
устанавливает все пакеты с именем, начинающимся с «postgres-», вместо того, чтобы искать в текущем каталоге файлы с именем «postgres-something».
Экранирование символов
Некоторые символы нельзя вводить непосредственно в командной строке. Для таких символов предоставляются так называемые escape-последовательности. Вот они:
-
\aпредставляет символ предупреждения. -
\eпредставляет символ escape. -
\fпредставляет символ перевода страницы. -
\nпредставляет символ новой строки. -
\rпредставляет символ возврата каретки. -
\tпредставляет символ табуляции. -
\vпредставляет символ вертикальной табуляции. -
\xHHили\XHH, гдеHH— шестнадцатеричное число, представляет байт данных со значением, указанным в этом числе. Например,\x9— это символ табуляции. Если используется многобайтовая кодировка, это можно использовать для ввода некорректных строк. Обычно fish запускается с кодировкой ASCII или UTF-8, поэтому всё до\X7f— это символ ASCII. -
\ooo, гдеooo— восьмеричное число, представляет символ ASCII со значением, указанным в этом числе. Например,\011— это символ табуляции. Максимально допустимое значение —\177. -
\uXXXX, гдеXXXX— шестнадцатеричное число, представляет 16-битный символ Unicode со значением, указанным в этом числе. Например,\u9— это символ табуляции. -
\UXXXXXXXX, гдеXXXXXXXX— шестнадцатеричное число, представляет 32-битный символ Unicode со значением, указанным в этом числе. Например,\U9— это символ табуляции. Максимально допустимое значение — U10FFFF. -
\cX, гдеX— буква алфавита, представляет управляющую последовательность, генерируемую при нажатии клавиши управления и указанной буквы. Например,\ci— это символ табуляции.
Некоторые символы имеют специальное значение для оболочки. Например, апостроф ' отключает расширение (см. Кавычки). Чтобы оболочка обрабатывала эти символы буквально, экранируйте их обратной косой чертой. Например, команда:
echo \'hello world\'
выводит 'hello world' (включая апострофы), а команда:
echo 'hello world'
выводит hello world (без апострофов). В первом случае оболочка обрабатывает апострофы как буквальные ' символы, а во втором — как специальные модификаторы расширения.
Специальные символы и их escape-последовательности:
-
\(обратная косая черта пробел) экранирует пробел. Это предотвращает разделение аргументов на пробеле, который был экранирован. -
\$экранирует символ доллара. -
\\экранирует символ обратной косой черты. -
\*экранирует символ звездочки. -
\?экранирует символ вопроса (это не обязательно, если включен флагqmark-noglobфлага). -
\~экранирует символ тильды. -
\#экранирует символ решётки. -
\(экранирует символ левой круглой скобки. -
\)экранирует символ правой круглой скобки. -
\{экранирует символ левой фигурной скобки. -
\}экранирует символ правой фигурной скобки. -
\[экранирует символ левой квадратной скобки. -
\]экранирует символ правой квадратной скобки. -
\<экранирует символ меньше. -
\>экранирует символ больше. -
\&экранирует символ амперсанда. -
\|экранирует символ вертикальной черты. -
\;экранирует символ точки с запятой. -
\"экранирует символ кавычки. -
\'экранирует символ апострофа.
В качестве специального случая \ сразу после буквальной новой строки является «продолжением» и сообщает fish игнорировать перевод строки и возобновить ввод в начале следующей строки (без ввода пробелов или завершения токена).
Перенаправление ввода/вывода
Большинство программ используют три потока ввода/вывода (I/O):
- Стандартный ввод (stdin) для чтения. По умолчанию считывается с клавиатуры.
- Стандартный вывод (stdout) для вывода. По умолчанию выводится на экран.
- Стандартная ошибка (stderr) для вывода ошибок и предупреждений. По умолчанию выводится на экран.
Каждый поток имеет номер, называемый дескриптором файла (FD): 0 для stdin, 1 для stdout и 2 для stderr.
Место назначения потока может быть изменено с помощью так называемого перенаправления. Например, echo hello > output.txt, перенаправляет стандартный вывод команды echo в текстовый файл.
- Для чтения стандартного ввода из файла используйте
<SOURCE_FILE. - Для записи стандартного вывода в файл используйте
>DESTINATION. - Для записи стандартной ошибки в файл используйте
2>DESTINATION. [1] - Для добавления стандартного вывода в файл используйте
>>DESTINATION_FILE. - Для добавления стандартной ошибки в файл используйте
2>>DESTINATION_FILE. - Чтобы не перезаписывать («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.
Например:
# Write `foo`'s standard error (file descriptor 2)
# to a file called "output.stderr":
foo 2> output.stderr
# if $num doesn't contain a number,
# this test will be false and print an error,
# so by ignoring the error we can be sure that we're dealing
# with a number in the "if" block:
if test "$num" -gt 2 2>/dev/null
# do things with $num as a number greater than 2
else
# do things if $num is <= 2 or not a number
end
# Save `make`s output in a file:
make &>/log
# Redirections stack and can be used with blocks:
begin
echo stdout
echo stderr >&2 # <- this goes to stderr!
end >/dev/null # ignore stdout, so this prints "stderr"
Перенаправление встроенной функции, функции или блока в дескриптор файла выше 2 — ошибка. Однако это поддерживается для внешних команд.
Перенаправление через трубопровод
Другой способ перенаправить потоки — это трубопровод. Трубопровод соединяет потоки друг с другом. Обычно стандартный вывод одной команды соединяется со стандартным вводом другой. Это делается путём разделения команд символом трубопровода |. Например:
cat foo.txt | head
Команда cat foo.txt отправляет содержимое foo.txt в stdout. Этот вывод используется в качестве ввода для программы head, которая выводит первые 10 строк своего ввода.
Возможна передача другого дескриптора вывода путём добавления его номера FD и символа перенаправления вывода перед символом трубопровода. Например:
make fish 2>| less
попытается создать fish, а любые ошибки будут отображаться с помощью программы less.
Для удобства трубопровод &| перенаправляет stdout и stderr в один и тот же процесс. Это отличается от bash, который использует |&.
Здесь «программа просмотра» — это программа, которая принимает вывод и «странирует» его. less не просто страничит, она позволяет произвольный просмотр (даже назад!).
Объединение трубопроводов и перенаправлений
Можно использовать несколько перенаправлений и трубопровод одновременно. В этом случае они обрабатываются в таком порядке:
- Сначала устанавливается трубопровод.
- Затем перенаправления оцениваются слева направо.
Это важно, когда перенаправления ссылаются на другие дескрипторы файлов с помощью синтаксиса &N. Когда вы говорите >&2, это перенаправит stdout туда, где в данный момент находится stderr.
Рассмотрим эту вспомогательную функцию:
# Just make a function that prints something to stdout and stderr
function print
echo out
echo err >&2
end
Теперь рассмотрим несколько случаев:
# Redirect both stderr and stdout to less # (can also be spelt as `&|`) print 2>&1 | less # Show the "out" on stderr, silence the "err" print >&2 2>/dev/null # Silence both print >/dev/null 2>&1
Управление задачами
При запуске задачи в fish, сам fish приостанавливается и передает управление терминалом только что запущенной программе. Иногда вы хотите продолжить работу в командной строке и запустить задачу в фоновом режиме. Для создания фоновой задачи добавьте амперсанд (&) к вашей команде. Это сообщит fish о запуске задачи в фоновом режиме. Фоновые задачи очень полезны при запуске программ с графическим интерфейсом пользователя.
Пример:
emacs &
запустит текстовый редактор emacs в фоновом режиме. fg можно использовать для возврата к нему в фоновый режим при необходимости.
Большинство программ позволяют приостановить выполнение программы и вернуть управление fish, нажав Ctrl+Z (также известное как ^Z). Вернувшись в командную строку fish, вы можете запустить другие программы и сделать всё, что захотите. Если затем захотите вернуться к приостановленной команде, используйте команду fg (фоновый режим).
Если вы хотите поместить приостановленную задачу в фоновый режим, используйте команду bg.
Чтобы получить список всех запущенных задач, используйте команду jobs. Эти задачи могут быть удалены с помощью команды disown.
В настоящее время функции не могут запускаться в фоновом режиме. Функции, которые остановлены и затем перезапущены в фоновом режиме с помощью команды bg, не будут выполняться правильно.
Если за символом & следует неразделимый символ, он не интерпретируется как оператор фонового запуска. Разделителями являются пробелы и символы ;<>&|.
Функции
Функции — это программы, написанные в синтаксисе fish. Они группируют различные команды и их аргументы под одним именем.
Например, вот простая функция для перечисления каталогов:
function ll
ls -l $argv
end
Первая строка сообщает fish о определении функции под именем ll, чтобы её можно было использовать, просто набрав ll в командной строке. Вторая строка сообщает fish, что команда ls -l $argv должна быть вызвана при вызове ll. $argv — это переменная списка, которая всегда содержит все аргументы, переданные функции. В приведённом примере они просто передаются команде ls. end в третьей строке завершает определение.
Вызов этой функции как ll /tmp/ приведет к выполнению команды ls -l /tmp/, которая выведет содержимое каталога /tmp.
Это пример функции, известной как псевдоним.
Подсказка fish также определена в функции, называемой fish_prompt. Она выполняется при отображении подсказки, и её вывод формирует подсказку:
function fish_prompt
# A simple prompt. Displays the current directory
# (which fish stores in the $PWD variable)
# and then a user symbol - a '►' for a normal user and a '#' for root.
set -l user_char '►'
if fish_is_root_user
set user_char '#'
end
echo (set_color yellow)$PWD (set_color purple)$user_char
end
Для редактирования функции можно использовать funced, а для сохранения — funcsave. Это сохранит её в файле функций, который fish будет автоматически загружать при необходимости.
Встроенная команда functions может показать текущее определение функции (а команда type также выполнит эту операцию, если ей передать функцию).
Дополнительную информацию о функциях см. в документации по встроенной команде function.
Определение псевдонимов
Одно из наиболее распространенных применений функций — небольшое изменение поведения уже существующей команды. Например, можно переопределить команду ls для отображения цветов. Переключатель для включения цвета в системах GNU — --color=auto. Псевдоним для ls может выглядеть так:
function ls
command ls --color=auto $argv
end
Некоторые важные моменты, которые следует учесть при работе с псевдонимами:
- Всегда добавляйте переменную $argv в список параметров обернутой команды. Это гарантирует, что, если пользователь указывает дополнительные параметры функции, они передаются в исходную команду.
- Если у псевдонима то же имя, что и у алиасируемой команды, необходимо добавить префикс
commandк вызову программы, чтобы указать fish, что функция не должна вызывать саму себя, а команду с тем же именем. Если вы забудете это сделать, функция будет вызывать сама себя до бесконечности. Обычно fish достаточно умён, чтобы разобраться с этим (что, надеемся, в ваших интересах).
Для удобного создания таких функций можно использовать команду alias. В отличие от других оболочек, это просто создаёт функции — fish не имеет отдельной концепции «псевдонима», мы просто используем это слово для простой функции оборачивания, как это. Команда alias сразу же создает функцию. Рассмотрите возможность использования alias --save или funcsave для сохранения созданной функции в файл автоматической загрузки вместо повторного создания псевдонима каждый раз.
В качестве альтернативы попробуйте сокращения. Это слова, которые расширяются при наборе, а не фактические функции внутри оболочки.
Автоматическая загрузка функций
Функции могут быть определены в командной строке или в конфигурационном файле, но они также могут загружаться автоматически. Это имеет некоторые преимущества:
- Автоматически загружаемая функция становится доступной для всех запущенных оболочек.
- Если определение функции изменено, все запущенные оболочки автоматически перезагрузят изменённую версию через некоторое время.
- Улучшается время запуска и использование памяти и т. д.
Когда fish нужно загрузить функцию, он ищет файлы с именем, состоящим из имени функции плюс суффикс .fish, в каталогах, указанных в переменной списка $fish_function_path и загружает первый найденный.
Например, если вы попытаетесь выполнить что-то с именем 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, а также знакомый синтаксис &&/||.
Оператор if
Оператор if выполняет блок команд, если условие истинно.
Как и в других оболочках, но в отличие от типичных языков программирования, условие здесь — это команда. Fish выполняет её, и если она возвращает значение истинности код возврата (то есть 0), то выполняется блок if. Например:
if test -e /etc/os-release
cat /etc/os-release
end
Здесь используется команда test, чтобы проверить, существует ли файл /etc/os-release. Если он существует, выполняется cat, который выводит его содержимое на экран.
В отличие от других оболочек, команда-условие завершается после выполнения первого задания, здесь нет then. Комбинирующие операторы, такие как and и or, расширяют возможности условия.
if часто используется с командой test, которая может проверять условия:
if test 5 -gt 2
echo "Yes, 5 is greater than 2"
end
if также может принимать else if с дополнительными условиями и оператор else, который выполняется, когда все другие условия ложны:
if test "$number" -gt 10 echo Your number was greater than 10 else if test "$number" -gt 5 echo Your number was greater than 5 else if test "$number" -gt 1 echo Your number was greater than 1 else echo Your number was smaller or equal to 1 end
Ключевое слово not может использоваться для инвертирования статуса:
# 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 `not` then turns 0 into 1 or anything else into 0.
# The `-q` switch stops it from printing any matches.
if not grep -q fish myanimals
echo "You don't have fish!"
else
echo "You have fish!"
end
Оператор switch
Команда switch используется для выполнения одного из нескольких блоков команд в зависимости от значения строки. Она может содержать несколько блоков case, которые выполняются при совпадении строки. Они могут содержать подстановки. Например:
switch (uname)
case Linux
echo Hi Tux!
case Darwin
echo Hi Hexley!
case DragonFly '*BSD'
echo Hi Beastie! # this also works for FreeBSD and NetBSD
case '*'
echo Hi, stranger!
end
В отличие от других оболочек или языков программирования, здесь нет проходки — выполняется первый совпадающий case блок, а затем управление переходит за пределы switch.
Комбинирующие операторы (and / or / && / ||)
Для простых проверок можно использовать комбинирующие операторы. and или && выполняют вторую команду, если первая успешно завершилась, в то время как or или || выполняют её, если первая завершилась неудачно. Например:
# $XDG_CONFIG_HOME is a standard place to store configuration. # If it's not set applications should use ~/.config. set -q XDG_CONFIG_HOME; and set -l configdir $XDG_CONFIG_HOME or set -l configdir ~/.config
Обратите внимание, что комбинирующие операторы являются ленивыми — выполняется только та часть, которая необходима для определения конечного статуса.
Сравните:
if sleep 2; and false
echo 'How did I get here? This should be impossible'
end
и:
if false; and sleep 2
echo 'How did I get here? This should be impossible'
end
Они выполняют в основном одно и то же, но первый вариант занимает на 2 секунды больше, потому что команда sleep всегда должна быть выполнена.
Или в случае, когда требуется прерывание:
if command -sq foo; and foo
Если бы эта цепочка продолжилась после выяснения того, что команды «foo» не существует, она попыталась бы выполнить foo и получила бы ошибку, потому что она не найдена!
Комбинирующие операторы работают пошагово, поэтому не рекомендуется создавать длинные цепочки, потому что они могут привести к нежелательным результатам. Подумайте о:
test -e /etc/my.config or echo "OH NO WE NEED A CONFIG FILE" and return 1
Это приведет к выполнению return 1 и в случае успеха test. Это происходит потому, что Fish выполняет test -e /etc/my.config, устанавливает $status в 0, затем пропускает echo, $status остается 0, и затем выполняет return 1 , поскольку $status всё ещё равен 0.
Если вам нужны более сложные условия или вы хотите выполнить несколько действий после неудачи, воспользуйтесь оператором if. В этом случае это было бы:
if not test -e /etc/my.config
echo "OH NO WE NEED A CONFIG FILE"
return 1
end
Циклы и блоки
Как и большинство языков программирования, Fish также имеет знакомые циклы while и for.
while работает как повторённый оператор if:
while true
echo Still running
sleep 1
end
будет выводить «Still running» каждую секунду. Можно прервать его с помощью ctrl-c.
for циклы работают как в других оболочках, что больше похоже на циклы for в Python, чем, например, в C:
for file in *
echo file: $file
end
будет выводить каждый файл в текущей директории. Часть после in — это просто список аргументов, так что там можно использовать любые расширения:
set moreanimals bird fox
for animal in {cat,}fish dog $moreanimals
echo I like the $animal
end
Если вам нужен список чисел, вы можете использовать команду seq для его создания:
for i in (seq 1 5)
echo $i
end
break доступен для выхода из цикла, а continue для перехода к следующей итерации.
Перенаправления ввода-вывода (включая каналы) также могут применяться к циклам:
while read -l line
echo line: $line
end < file
Кроме того, есть блок begin, который просто группирует команды, что позволяет перенаправлять данные в блок или использовать новую область видимости переменных без повторений:
begin set -l foo bar # this variable will only be available in this block! end
Расширение параметров
Когда fish получает команду из командной строки, он расширяет параметры перед отправкой их в команду. Существует несколько различных типов расширений:
-
Подстановки шаблонов, для создания имён файлов из шаблонов -
*.jpg -
Расширение переменных, для использования значения переменной -
$HOME -
Подстановка команд, для использования вывода другой команды -
$(cat /path/to/file) -
Расширение фигурных скобок, для записи списков с общими префиксами или суффиксами более кратко
{/usr,}/bin -
Расширение тильды, для преобразования
~в начале путей в путь к домашнему каталогу~/bin
Расширение параметров ограничено 524288 элементами. Существует ограничение на количество аргументов, разрешенных операционной системой для любой команды, и 524288 значительно превышает это ограничение. Это мера для предотвращения зависания оболочки при выполнении бесполезных вычислений.
Подстановки шаблонов («Глоббинговые» подстановки)
Когда параметр содержит незаключённый * звездочку (или «звёздочку») или ? вопросительный знак, fish использует их как подстановки шаблонов для сопоставления файлов.
-
*соответствует любому числу символов (включая ноль) в имени файла, кроме/. -
**соответствует любому количеству символов (включая ноль), а также спускается в подкаталоги. Если**является отдельным сегментом, этот сегмент может соответствовать нулю раз для совместимости с другими оболочками. -
?может соответствовать любому одиночному символу, кроме/. Эта функция устарела и может быть отключена черезqmark-noglobфлаг функции, поэтому?будет просто обычным символом.
Сопоставления с подстановками шаблонов сортируются без учёта регистра. При сортировке сопоставлений, содержащих числа, они сортируются естественным образом, так что строки ‘1’, ‘5’ и ‘12’ будут отсортированы как 1, 5, 12.
Скрытые файлы (где имя начинается с точки) не учитываются при подстановке шаблонов, если в строке подстановки шаблона нет точки в соответствующем месте.
Примеры:
-
a*соответствует любым файлам, начинающимся с «a», в текущем каталоге. -
**соответствует любым файлам и каталогам в текущем каталоге и всех его подкаталогах. -
~/.*соответствует всем скрытым файлам (также известным как «dotfiles») и каталогам в вашем домашнем каталоге.
Для большинства команд, если ни одна подстановка шаблона не удается, команда не выполняется, $status устанавливается в ненулевое значение и выводится предупреждение. Это поведение аналогично тому, что делает bash с shopt -s failglob. Есть исключения, а именно set и path, перезаписывающие переменные в перезаписи, count и for. Их подстановки шаблонов вместо этого будут расширяться до нуля аргументов (так что команда их вообще не увидит), как и в shopt -s nullglob в bash.
Примеры:
# List the .foo files, or warns if there aren't any.
ls *.foo
# List the .foo files, if any.
set foos *.foo
if count $foos >/dev/null
ls $foos
end
В отличие от bash (по умолчанию), fish не будет передавать буквальный символ подстановки шаблона, если совпадений не найдено, поэтому для команды, подобной apt install, которая выполняет сопоставление сама, вам нужно добавить кавычки:
apt install "ncurses-*"
Расширение переменных
Одним из важнейших расширений в fish является «расширение переменных». Это замена знака доллара ($) за которым следует имя переменной, на _значение_ этой переменной.
В простейшем случае это выглядит примерно так:
echo $HOME
что заменит $HOME на домашний каталог текущего пользователя и передаст его в echo, который затем выведет его.
Некоторые переменные, такие как $HOME, уже заданы, потому что fish устанавливает их по умолчанию или потому, что родительский процесс fish передал их fish при его запуске. Вы можете определить свои собственные переменные, задав их с помощью set:
set my_directory /home/cooluser/mystuff ls $my_directory # shows the contents of /home/cooluser/mystuff
Дополнительные сведения о работе с настройкой переменных см. в разделе Переменные оболочки и последующих разделах.
Иногда переменная не имеет значения, потому что она не определена или пуста, и она расширяется до ничего:
echo $nonexistentvariable # Prints no output.
Чтобы отделить имя переменной от текста, вы можете заключить переменную в двойные кавычки или фигурные скобки:
set WORD cat
echo The plural of $WORD is "$WORD"s
# Prints "The plural of cat is cats" because $WORD is set to "cat".
echo The plural of $WORD is {$WORD}s
# ditto
Без кавычек или фигурных скобок fish попытается расширить переменную с именем $WORDs, которая может не существовать.
Последний синтаксис {$WORD} является специальным случаем расширения фигурных скобок.
Если $WORD здесь не определена или является пустым списком, «s» не выводится. Однако она выводится, если $WORD — пустая строка (например, после set WORD "").
Дополнительные сведения о переменных оболочки см. в разделе Переменные оболочки.
Присвоение кавычек переменным
В отличие от всех других расширений, расширение переменных также происходит в строках с двойными кавычками. Внутри двойных кавычек ("these"), переменные всегда расширяются ровно до одного аргумента. Если они пусты или не определены, результатом будет пустая строка. Если они содержат один элемент, они расширятся до этого элемента. Если у них более одного элемента, элементы будут объединены пробелами, если переменная не является переменной пути — в этом случае будет использоваться двоеточие (:) вместо [3].
За пределами двойных кавычек переменные будут расширяться до тех аргументов, которые у них есть. Это означает, что пустой список расширится до ничего, переменная с одним элементом расширится до этого элемента, а переменная с несколькими элементами расширится до каждого из этих элементов по отдельности.
Если переменная расширяется до ничего, она аннулирует любые другие строки, присоединенные к ней. Дополнительные сведения см. в разделе Декартово произведение.
В отличие от других оболочек, fish не выполняет «разбиение слов». Как только переменной присвоено определённое множество элементов, эти элементы расширяются как есть. Они не разделены пробелами, символами новой строки или чем-либо ещё:
> set foo one\nthing > echo $foo one thing > printf '|%s|\n' $foo |one thing|
Это означает, что цитирование не является такой необходимой мерой, как в других оболочках. В большинстве случаев не цитирование переменной является правильным. Исключением является случай, когда необходимо гарантировать, что переменная передаётся как один элемент, даже если она может быть неопределена или содержать несколько элементов. Это часто происходит с test:
set -l foo one two three test -n $foo # prints an error that it got too many arguments, because it was executed like test -n one two three test -n "$foo" # works, because it was executed like test -n "one two three"
В отличие от 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, использовать их как имена переменных, а затем получить пятый элемент этих переменных).
Подстановка команд
Подстановка команды — это расширение, которое использует выходные данные одной команды в качестве аргументов для другой. Например:
echo (pwd)
Это выполняет команду pwd, берёт её вывод (точнее, то, что она вывела в стандартный поток вывода «stdout») и использует его в качестве аргументов для команды echo. Таким образом, внутренняя команда (pwd) выполняется первой и должна завершиться до запуска внешней команды.
Если внутренняя команда выводит несколько строк, fish будет использовать каждую отдельную строку как отдельный аргумент для внешней команды. В отличие от других оболочек, значение $IFS не используется [4], fish выполняет разделение по символам новой строки.
Подстановка команды также может быть записана с помощью знака доллара, как outercommand $(innercommand). Этот вариант также разрешён внутри двойных кавычек. При использовании двойных кавычек вывод команды не разбивается на строки, но пустые строки в конце всё равно удаляются.
Если вывод направлен в string split или string split0 как последний шаг, эти разделения используются так, как они появляются, вместо разделения строк.
Код возврата последней выполненной подстановки команды доступен в переменной status, если подстановка происходит в контексте команды set (следовательно, if set -l (something) проверяет, вернула ли something значение true).
Чтобы использовать только некоторые строки вывода, обратитесь к разделам срезов.
Примеры:
# Outputs 'image.png'. echo (basename image.jpg .jpg).png # Convert all JPEG files in the current directory to the # PNG format using the 'convert' program. for i in *.jpg; convert $i (basename $i .jpg).png; end # Set the ``data`` variable to the contents of 'data.txt' # without splitting it into a list. set data "$(cat data.txt)" # Set ``$data`` to the contents of data, splitting on NUL-bytes. set data (cat data | string split0)
Иногда нужно передать вывод одной команды другой команде, которая принимает только файлы. Если это только один файл, то его можно обычно передать через канал, как:
grep fish myanimallist1 | wc -l
но если вам нужны несколько файлов или команда не считывает данные со стандартного ввода, полезна «подстановка процесса». Другие оболочки позволяют это сделать с помощью foo <(bar) <(baz), а fish использует команду psub:
# Compare just the lines containing "fish" in two files: diff -u (grep fish myanimallist1 | psub) (grep fish myanimallist2 | psub)
Это создаёт временный файл, сохраняет в нём вывод команды и выводит имя файла, чтобы он был передан внешней команде.
В fish есть лимит по умолчанию в 100 МБ на данные, которые будут считаны в подстановке команды. Если этот лимит будет достигнут, команда (вся, а не только подстановка команды — внешняя команда вообще не будет выполнена) завершится с ошибкой, и $status будет установлено в значение 122. Это делается для того, чтобы подстановки команд не привели к исчерпанию памяти системы, так как у вашей операционной системы обычно гораздо меньший лимит, поэтому чтение большего объёма будет бесполезным и вредным. Этот лимит можно настроить с помощью переменной fish_read_limit (0 означает отсутствие лимита). Этот лимит также влияет на команду read.
Одно исключение: Установка $IFS в пустое значение отключит разделение по строкам. Это устаревший метод, используйте вместо него string split вместо него.
Расширение фигурных скобок
Фигурные скобки могут использоваться для записи списков, разделённых запятыми. Они будут расширены, и каждый элемент станет новым параметром со присоединённой к нему окружающей строкой. Это полезно для экономии набора текста и для отделения имени переменной от окружающего текста.
Примеры:
> echo input.{c,h,txt}
input.c input.h input.txt
# Move all files with the suffix '.c' or '.h' to the subdirectory src.
> mv *.{c,h} src/
# Make a copy of `file` at `file.bak`.
> cp file{,.bak}
> set -l dogs hot cool cute "good "
> echo {$dogs}dog
hotdog cooldog cutedog good dog
Если между фигурными скобками нет «,» или расширения переменной, они не будут расширены:
# This {} isn't special
> echo foo-{}
foo-{}
# This passes "HEAD@{2}" to git
> git reset --hard HEAD@{2}
> echo {{a,b}}
{a} {b} # because the inner brace pair is expanded, but the outer isn't.
Если после расширения между фигурными скобками ничего нет, аргумент будет удалён (см. раздел декартова произведения):
> echo foo-{$undefinedvar}
# Output is an empty line, just like a bare `echo`.
Если между фигурной скобкой и запятой или двумя запятыми ничего нет, это интерпретируется как пустой элемент:
> echo {,,/usr}/bin
/bin /bin /usr/bin
Чтобы использовать «,» как элемент, кавычки или экранирование его.
Объединение списков (Декартово произведение)
Когда списки расширяются с присоединёнными к ним другими частями, они расширяются с этими частями всё ещё присоединёнными. Даже если два списка присоединены друг к другу, они расширяются во всех комбинациях. Это называется «декартовым произведением» (как в математике), и работает в основном так же, как расширение фигурных скобок.
Примеры:
# Brace expansion is the most familiar:
# All elements in the brace combine with the parts outside of the braces
>_ echo {good,bad}" apples"
good apples bad apples
# The same thing happens with variable expansion.
>_ set -l a x y z
>_ set -l b 1 2 3
# $a is {x,y,z}, $b is {1,2,3},
# so this is `echo {x,y,z}{1,2,3}`
>_ echo $a$b
x1 y1 z1 x2 y2 z2 x3 y3 z3
# Same thing if something is between the lists
>_ echo $a"-"$b
x-1 y-1 z-1 x-2 y-2 z-2 x-3 y-3 z-3
# Or a brace expansion and a variable
>_ echo {x,y,z}$b
x1 y1 z1 x2 y2 z2 x3 y3 z3
# A combined brace-variable expansion
>_ echo {$b}word
1word 2word 3word
# Special case: If $c has no elements, this expands to nothing
>_ echo {$c}word
# Output is an empty line
Иногда это может быть нежелательно, особенно потому, что токены могут исчезнуть после расширения. В таких случаях следует использовать двойные кавычки для переменных — echo "$c"word.
Это также происходит после подстановки команд. Чтобы предотвратить исчезновение токенов, заставьте внутреннюю команду возвращать конечную новую строку или сохраните вывод в переменной и поставьте двойные кавычки.
Например:
>_ set b 1 2 3 >_ echo (echo x)$b x1 x2 x3 >_ echo (printf '%s' '')banana # the printf prints nothing, so this is nothing times "banana", # which is nothing. >_ echo (printf '%s\n' '')banana # the printf prints a newline, # so the command substitution expands to an empty string, # so this is `''banana` banana
Это может быть очень полезно. Например, если вы хотите пройтись по всем файлам во всех каталогах в PATH, используйте
for file in $PATH/*
Поскольку PATH представляет собой список, это расширяется до всех файлов во всех каталогах в нём. И если в PATH нет каталогов, правильным ответом здесь будет расширение до нулевых файлов.
Срезы
Иногда необходимо получить доступ только к некоторым элементам списка (все переменные fish являются списками) или некоторых строк, которые выводит подстановка команды. В fish это возможно, записав набор индексов в квадратные скобки, как:
# Make $var a list of four elements set var one two three four # Print the second: echo $var[2] # prints "two" # or print the first three: echo $var[1..3] # prints "one two three"
В квадратных скобках индексов fish понимает диапазоны, записанные как a..b («a» и «b» — это индексы). Они расширяются в последовательность индексов от a до b (поэтому a a+1 a+2 ... b), возрастающие, если b больше, и убывающие, если a больше. Также можно использовать отрицательные индексы — они берутся с конца списка, поэтому -1 — это последний элемент, а -2 — элемент перед ним. Если индекс не существует, диапазон ограничен следующим возможным индексом.
Если список содержит 5 элементов, индексы варьируются от 1 до 5, поэтому диапазон 2..16 будет охватывать только элементы с 2-го по 5-ый.
Если конец отрицателен, диапазон всегда возрастает, поэтому 2..-2 будет охватывать элементы с 2-го по 4-ый, а 2..-16 не будет охватывать ничего, так как нет способа перейти от второго элемента к несуществующему, увеличивая индекс. Если начало отрицательно, диапазон всегда убывает, поэтому -2..1 будет охватывать элементы с 4-го по 1-ый, а -16..2 не будет охватывать ничего, так как нет способа перейти от несуществующего элемента ко второму, уменьшая индекс.
Пропущенный начальный индекс в диапазоне по умолчанию равен 1. Это допускается, если диапазон является первым выражением индекса в последовательности. Аналогично, пропущенный конечный индекс по умолчанию равен -1 для последнего индекса в последовательности.
Также возможно использование нескольких диапазонов, разделённых пробелами.
Некоторые примеры:
echo (seq 10)[1 2 3] # Prints: 1 2 3 # Limit the command substitution output echo (seq 10)[2..5] # Uses elements from 2 to 5 # Output is: 2 3 4 5 echo (seq 10)[7..] # Prints: 7 8 9 10 # Use overlapping ranges: echo (seq 10)[2..5 1..3] # Takes elements from 2 to 5 and then elements from 1 to 3 # Output is: 2 3 4 5 1 2 3 # Reverse output echo (seq 10)[-1..1] # Uses elements from the last output line to # the first one in reverse direction # Output is: 10 9 8 7 6 5 4 3 2 1 # The command substitution has only one line, # so these will result in empty output: echo (echo one)[2..-1] echo (echo one)[-3..1]
То же самое работает при установке или расширении переменных:
# Reverse path variable set PATH $PATH[-1..1] # or set PATH[-1..1] $PATH # Use only n last items of the PATH set n -3 echo $PATH[$n..-1]
Переменные могут использоваться как индексы для расширения переменных, например:
set index 2 set letters a b c d echo $letters[$index] # returns 'b'
Однако использование переменных в качестве индексов для подстановки команд в настоящее время не поддерживается, поэтому:
echo (seq 5)[$index] # This won't work set sequence (seq 5) # It needs to be written on two lines like this. echo $sequence[$index] # returns '2'
При использовании косвенного расширения переменных с несколькими $ ($$name) необходимо указать все индексы до переменной, которую вы хотите разрезать:
> set -l list 1 2 3 4 5 > set -l name list > echo $$name[1] 1 2 3 4 5 > echo $$name[1..-1][1..3] # or $$name[1][1..3], since $name only has one element. 1 2 3
Расширение домашнего каталога
Символ ~ (тильда) в начале параметра, за которым следует имя пользователя, расширяется до домашнего каталога указанного пользователя. Одиночная ~, или ~, за которой следует обратный слэш, расширяется до домашнего каталога владельца процесса:
ls ~/Music # lists my music directory echo ~root # prints root's home directory, probably "/root"
Объединение различных расширений
Все вышеперечисленные расширения могут быть объединены. Если несколько расширений приводят к более чем одному параметру, создаются все возможные комбинации.
При объединении нескольких расширений параметров расширения выполняются в следующем порядке:
- Подстановки команд
- Расширения переменных
- Расширение в квадратных скобках
- Расширение с подстановкой шаблонов
Расширения выполняются справа налево, вложенные расширения в квадратных скобках выполняются изнутри наружу.
Пример:
Если в текущем каталоге находятся файлы ‘foo’ и ‘bar’, команда echo a(ls){1,2,3} выведет abar1 abar2 abar3 afoo1 afoo2 afoo3.
Переменные оболочки
Переменные — это способ сохранения данных и передачи их. Они могут использоваться только оболочкой или могут быть «экспортированы», чтобы копия переменной была доступна любому внешнему командному интерпретатору, который запускает оболочка. Экспортированная переменная называется «переменной среды».
Для установки значения переменной используйте команду set. Имя переменной не может быть пустым и может содержать только буквы, цифры и символы подчеркивания. Оно может начинаться и заканчиваться любым из этих символов.
Пример:
Чтобы установить переменную smurf_color в значение blue, используйте команду set smurf_color blue.
После установки переменной вы можете использовать значение переменной в оболочке с помощью расширения переменных.
Пример:
set smurf_color blue echo Smurfs are usually $smurf_color set pants_color red echo Papa smurf, who is $smurf_color, wears $pants_color pants
Таким образом, вы устанавливаете переменную с set, и используете ее с $ и именем.
Область действия переменных
В fish существуют четыре типа переменных: универсальные, глобальные, переменные функций и локальные переменные.
- Универсальные переменные общие для всех сеансов fish, которые пользователь запускает на одном компьютере. Они хранятся на диске и сохраняются даже после перезагрузки.
- Глобальные переменные специфичны для текущего сеанса fish. Их можно удалить, явно запросив
set -e. - Переменные функций специфичны для выполняемой в данный момент функции. Они удаляются («выходят из области видимости») по завершении текущей функции. Вне функции они не выходят из области видимости.
- Локальные переменные специфичны для текущего блока команд и автоматически удаляются, когда конкретный блок выходит из области видимости. Блок команд — это последовательность команд, которая начинается с одной из команд
for,while,if,function,beginилиswitch, и заканчивается командойend. Вне блока это то же самое, что область действия функции.
Переменные могут быть явно заданы как универсальные с помощью переключателя -U или --universal, глобальные с -g или --global, привязанные к функции с -f или --function и локальные для текущего блока с -l или --local. Правила области действия при создании или обновлении переменной следующие:
- Когда задаётся область действия, она используется. Если переменная с тем же именем существует в другой области действия, эта переменная не будет изменена.
- Когда область действия не задана, но переменная с этим именем существует, будет модифицирована переменная с наименьшей областью действия. Область действия не будет изменена.
- Когда область действия не задана и переменная с этим именем не существует, переменная создаётся в области действия функции, если внутри функции, или в глобальной области действия, если функция не выполняется.
Может быть много переменных с одинаковым именем, но разной областью действия. Когда вы используете переменную, будет использоваться переменная с наименьшей областью действия с этим именем. Если существует локальная переменная, она будет использоваться вместо глобальной или универсальной переменной с тем же именем.
Пример:
Существует несколько возможных применений для разных областей действия.
Обычно внутри функций следует использовать локальную область действия:
function something
set -l file /path/to/my/file
if not test -e "$file"
set file /path/to/my/otherfile
end
end
# or
function something
if test -e /path/to/my/file
set -f file /path/to/my/file
else
set -f file /path/to/my/otherfile
end
end
Если вы хотите установить что-то в config.fish или установить что-то в функции и иметь его доступным для остальной части сеанса, глобальная область действия — хороший выбор:
# Don't shorten the working directory in the prompt set -g fish_prompt_pwd_dir_length 0 # Set my preferred cursor style: function setcursors set -g fish_cursor_default block set -g fish_cursor_insert line set -g fish_cursor_visual underscore end # Set my language set -gx LANG de_DE.UTF-8
Если вы хотите установить некоторые настройки, универсальные переменные — неплохой вариант:
# Typically you'd run this interactively, fish takes care of keeping it. set -U fish_color_autosuggestion 555
Вот пример локальных и привязанных к функции переменных:
function test-scopes
begin
# This is a nice local scope where all variables will die
set -l pirate 'There be treasure in them thar hills'
set -f captain Space, the final frontier
# If no variable of that name was defined, it is function-local.
set gnu "In the beginning there was nothing, which exploded"
end
echo $pirate
# This will not output anything, since the pirate was local
echo $captain
# This will output the good Captain's speech since $captain had function-scope.
echo $gnu
# Will output Sir Terry's wisdom.
end
Когда функция вызывает другую, локальные переменные недоступны:
function shiver
set phrase 'Shiver me timbers'
end
function avast
set --local phrase 'Avast, mateys'
# Calling the shiver function here can not
# change any variables in the local scope
# so phrase remains as we set it here.
shiver
echo $phrase
end
avast
# Outputs "Avast, mateys"
В случае сомнений используйте переменные области действия функций. Когда вам нужно сделать переменную доступной везде, сделайте её глобальной. Когда вам нужно постоянно хранить конфигурацию, сделайте её универсальной. Когда вы хотите использовать переменную только в небольшом блоке, сделайте её локальной.
Переопределение переменных для одной команды
Если вы хотите переопределить переменную для одной команды, вы можете использовать операторы «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, потому что эти переменные будут становиться длиннее с каждым новым экземпляром оболочки. Вместо этого просто установите их один раз в командной строке.
Экспорт переменных
Переменные в fish могут быть экспортированы, поэтому они будут унаследованы любыми командами, запущенными fish. В частности, это необходимо для переменных, используемых для настройки внешних команд, таких как PAGER или GOPATH, а также для переменных, содержащих общие системные настройки, такие как PATH или LANGUAGE. Если внешней команде нужна переменная, она должна быть экспортирована. Экспортированные переменные также часто называют «переменными среды».
Это также относится к fish — при запуске он получает переменные среды от своего родителя (обычно терминала). Обычно это включает системную конфигурацию, такую как PATH и переменные локали.
Переменные могут быть явно настроены как экспортируемые с помощью переключателя -x или --export, или не экспортируемые с помощью переключателя -u или --unexport. Правила экспорта при установке переменной похожи на правила области действия переменных — при передаче параметра он уважается, в противном случае используется существующее состояние переменной. Если параметр не передан, и переменная ещё не существовала, она не экспортируется.
В качестве соглашения об именах, экспортированные переменные — заглавные, а не экспортированные — строчные.
Например:
set -gx ANDROID_HOME ~/.android # /opt/android-sdk set -gx CDPATH . ~ (test -e ~/Videos; and echo ~/Videos) set -gx EDITOR emacs -nw set -gx GOPATH ~/dev/go set -gx GTK2_RC_FILES "$XDG_CONFIG_HOME/gtk-2.0/gtkrc" set -gx LESSHISTFILE "-"
Примечание: Экспорт — это не область действия, а дополнительное состояние. Обычно имеет смысл делать экспортированные переменные глобальными, но локальные экспортированные переменные могут быть полезны, если вам нужно что-то более конкретное, чем переопределения. Они копируются в функции, поэтому функция не может изменить их снаружи, и по-прежнему доступны командам. Глобальные переменные доступны функциям, независимо от того, экспортируются они или нет.
Списки
Рыба может хранить список (или «массив», если хотите) нескольких строк внутри переменной:
> set mylist first second third > printf '%s\n' $mylist # prints each element on its own line first second third
Для доступа к одному элементу списка используйте индекс элемента в квадратных скобках, например:
echo $PATH[3]
Индексы списков в рыбе начинаются с 1, а не с 0, как в других языках. Это связано с тем, что требуется меньше вычитаний 1, и многие распространённые утилиты Unix, такие как seq работают лучше с ним (seq 5 печатает от 1 до 5, а не от 0 до 5). Неверный индекс игнорируется, не возвращая никакого значения (даже не пустой строки, просто вообще никакого аргумента).
Если вы не используете квадратные скобки, все элементы списка будут переданы команде как отдельные элементы. Это означает, что вы можете перебирать список с помощью for:
for i in $PATH
echo $i is in the path
end
Это перебирает каждую директорию в PATH по отдельности и печатает строку, говорящую, что она находится в пути.
Чтобы создать переменную smurf, содержащую элементы blue и small, просто напишите:
set smurf blue small
Также можно устанавливать или удалять отдельные элементы списка:
# Set smurf to be a list with the elements 'blue' and 'small' set smurf blue small # Change the second element of smurf to 'evil' set smurf[2] evil # Erase the first element set -e smurf[1] # Output 'evil' echo $smurf
Если вы указываете отрицательный индекс при расширении или присваивании переменной списка, индекс будет взят с конца списка. Например, индекс -1 — это последний элемент списка:
> set fruit apple orange banana > echo $fruit[-1] banana > echo $fruit[-2..-1] orange banana > echo $fruit[-1..1] # reverses the list banana orange apple
Как видите, вы можете использовать диапазон индексов, см. фрагменты для получения подробностей.
Все списки одномерные и не могут содержать другие списки, хотя можно имитировать вложенные списки с помощью разыменования — см. расширение переменной.
Когда список экспортируется как переменная среды, он разделяется пробелами или двоеточиями, в зависимости от того, является ли это переменной пути:
> set -x smurf blue small > set -x smurf_PATH forest mushroom > env | grep smurf smurf=blue small smurf_PATH=forest:mushroom
Рыба автоматически создает списки из всех переменных среды, имена которых оканчиваются на PATH (например, PATH, CDPATH или MANPATH), разбивая их по двоеточиям. Другие переменные не разбиваются автоматически.
Списки можно проверить с помощью команд count или contains:
> count $smurf 2 > contains blue $smurf # blue was found, so it exits with status 0 # (without printing anything) > echo $status 0 > contains -i blue $smurf 1
Прекрасно в списках то, что они передаются командам по одному элементу как один аргумент, поэтому, после того как вы установили свой список, вы можете просто передать его:
set -l grep_args -r "my string" grep $grep_args . # will run the same as `grep -r "my string"` .
В отличие от других оболочек, рыба не выполняет «разделение слов» — элементы списка остаются неизменными, даже если они содержат пробелы или табуляции.
Обработка аргументов
Важным списком является $argv, который содержит аргументы функции или скрипта. Например:
function myfunction
echo $argv[1]
echo $argv[3]
end
Эта функция принимает все полученные аргументы и печатает первый и третий:
> myfunction first second third first third > myfunction apple cucumber banana apple banana
Это относится к позиционным аргументам, но утилиты командной строки часто получают различные опции и флаги, и $argv будет содержать их, перемешанные с позиционными аргументами. Типичная обработка аргументов Unix допускает короткие опции (-h, также сгруппированные, как в ls -lah ), длинные опции (--help) и допускает, чтобы эти опции принимали аргументы (--color=auto или --position anywhere или complete -C"git " ), а также разделитель -- для обозначения конца опций. Обработка всего этого вручную сложна и подвержена ошибкам.
Более надёжный подход к обработке опций — argparse, который проверяет определённые опции и помещает их в различные переменные, оставляя только позиционные аргументы в $argv. Вот простой пример:
function mybetterfunction
# We tell argparse about -h/--help and -s/--second - these are short and long forms of the same option.
# The "--" here is mandatory, it tells it from where to read the arguments.
argparse h/help s/second -- $argv
# exit if argparse failed because it found an option it didn't recognize - it will print an error
or return
# If -h or --help is given, we print a little help text and return
if set -ql _flag_help
echo "mybetterfunction [-h|--help] [-s|--second] [ARGUMENT ...]"
return 0
end
# If -s or --second is given, we print the second argument,
# not the first and third.
# (this is also available as _flag_s because of the short version)
if set -ql _flag_second
echo $argv[2]
else
echo $argv[1]
echo $argv[3]
end
end
Опции будут удалены из $argv, поэтому $argv[2] теперь является вторым позиционным аргументом:
> mybetterfunction first -s second third second
Для получения дополнительной информации об argparse, например, о том, как обрабатывать аргументы опций, см. документацию по argparse.
Переменные PATH
Переменные PATH — это специальный тип переменных, используемых для поддержки списков путей, разделенных двоеточиями, включая 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 -
Список каталогов, в которых следует искать команды. Это общая переменная Unix, используемая также и другими инструментами.
-
CDPATH -
Список каталогов, в которых встроенная команда cd ищет новый каталог.
- Переменные локали
-
Переменные локали
LANG,LC_ALL,LC_COLLATE,LC_CTYPE,LC_MESSAGES,LC_MONETARY,LC_NUMERICиLANGустанавливают языковые параметры для оболочки и подпрограмм. Более подробную информацию см. в разделе Переменные локали.
- Переменные цвета
-
Несколько переменных, начинающихся с префиксов
fish_colorиfish_pager_color. Более подробную информацию см. в Переменные для изменения цветов выделения.
-
fish_term24bit -
Если это значение равно 1, fish будет считать, что терминал понимает 24-битные цветовые последовательности RGB и не будет переводить их в палитру из 256 или 16 цветов. Часто это определяется автоматически.
-
fish_term256 -
Если это значение равно 1, fish будет считать, что терминал понимает 256 цветов, и не будет переводить соответствующие цвета в палитру из 16 цветов. Обычно это определяется автоматически.
-
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_sequence_key_delay_ms -
устанавливает, сколько времени fish ожидает нажатия другой клавиши после получения клавиши, которая является частью более длинной последовательности, для уточнения. Например, если вы привязали
\cx\ceк открытию редактора, fish будет ожидать в течение этого времени в миллисекундах, чтобы увидеть ctrl-e после ctrl-x. Если время истекает, он обработает это как ctrl-x (по умолчанию это скопирует текущую командную строку в буфер обмена). См. также Последовательности клавиш.
-
fish_complete_path -
определяет, где fish ищет завершение. При попытке завершения команды fish ищет файлы в каталогах в этой переменной.
-
fish_cursor_selection_mode -
управляет тем, является ли выделение включительным или исключительным по отношению к символу под курсором (см. Копирование и вставка).
-
fish_function_path -
определяет, где fish ищет функции. Когда fish автозагружает функцию, он будет искать файлы в этих каталогах.
-
fish_greeting -
сообщение приветствия, выводимое при запуске. Это печатается функцией с тем же именем, которую можно переопределить для более сложных изменений (см. funced)
-
fish_history -
текущее имя сессии истории. Если установлено, все последующие команды в интерактивной сессии fish будут записываться в отдельный файл, идентифицированный значением переменной. Если не установлено, используется имя сессии по умолчанию «fish». Если установлено пустым значением, история не сохраняется на диск (но всё ещё доступна в интерактивной сессии).
-
fish_trace -
если установлено и не пустое, заставит fish выводить команды перед их выполнением, подобно
set -xв bash. Трассировка выводится в путь, заданный параметром--debug-outputдля fish или переменнойFISH_DEBUG_OUTPUT. По умолчанию выводится в stderr.
-
FISH_DEBUG -
Управляет категориями отладки, которые fish включает для вывода, аналогично параметру
--debug.
-
FISH_DEBUG_OUTPUT -
Указывает файл для вывода отладочной информации.
-
fish_user_paths -
список каталогов, добавляемых перед
PATH. Это может быть универсальная переменная.
-
umask -
текущая маска создания файлов. Предпочтительный способ изменения переменной umask — через функцию umask. Попытка установить umask в неверное значение всегда завершится неудачей.
-
BROWSER -
ваш предпочтительный веб-браузер. Если эта переменная установлена, fish будет использовать указанный браузер вместо системного по умолчанию для отображения документации fish.
Fish также предоставляет дополнительную информацию через значения определённых переменных среды. Большинство из этих переменных являются только для чтения, и их значение нельзя изменить с помощью set.
-
_ -
имя выполняемой в данный момент команды (хотя это устарело, и предпочтительнее использовать
status current-command).
-
argv -
список аргументов для оболочки или функции.
argvопределена только при вызове функции или если fish был вызван со списком аргументов, напримерfish myscript.fish foo bar. Эту переменную можно изменить.
-
CMD_DURATION -
время выполнения последней команды в миллисекундах.
- COLUMNS и LINES
-
текущие размеры терминала по высоте и ширине. Эти значения используются fish только если операционная система не сообщает размеры терминала. В этом случае обе переменные должны быть установлены, в противном случае используется значение по умолчанию 80x24. Они обновляются при изменении размера окна.
-
fish_kill_signal -
сигнал, который завершил последнюю фоновую задачу, или 0, если задача завершилась нормально.
-
fish_killring -
список записей в кольце обмена fish(кольце обмена) вырезанного текста.
-
fish_read_limit -
сколько байтов будет обрабатывать fish с помощью команды read или в подстановке команд.
-
fish_pid -
идентификатор процесса (PID) оболочки.
-
history -
список последних введённых команд.
-
HOME -
домашний каталог пользователя. Эта переменная может быть изменена.
-
hostname -
имя хоста машины.
-
IFS -
внутренний разделитель полей, используемый для разделения слов с помощью встроенной команды read. Установка этой переменной в пустую строку также отключит разделение строк в подстановке команд. Эта переменная может быть изменена.
-
last_pid -
идентификатор процесса (PID) последнего фонового процесса.
-
PWD -
текущий рабочий каталог.
-
pipestatus -
список кодов завершения всех процессов, составляющих последнюю выполненную цепочку команд. См. код завершения.
-
SHLVL -
уровень вложенности оболочек. Fish увеличивает это значение в интерактивных оболочках, в противном случае просто передаёт его.
-
status -
код завершения последней завершившейся фоновой задачи. Если задача завершилась по сигналу, код завершения будет равен 128 плюс номер сигнала.
-
status_generation -
счётчик «поколения»
$status. Он будет инкрементироваться только тогда, когда предыдущая команда сгенерировала явное значение кода завершения. (Например, фоновые задачи не будут увеличивать это значение).
-
TERM -
тип текущего терминала. Когда fish пытается определить, как работает терминал — сколько он поддерживает цветов, какие последовательности он отправляет для клавиш и других вещей — он смотрит на эту переменную и соответствующую информацию в базе данных terminfo (см.
man terminfo).Примечание: обычно его не нужно менять, так как терминал устанавливает его в правильное значение.
-
USER -
текущее имя пользователя. Эта переменная может быть изменена.
-
EUID -
текущий эффективный идентификатор пользователя, установленный fish при запуске. Эта переменная может быть изменена.
-
version -
версия запущенного fish (также доступна как
FISH_VERSIONдля обратной совместимости).
В соответствии с соглашением, имена переменных с заглавными буквами обычно используются для экспортируемых переменных, в то время как переменные со строчными буквами не экспортируются. (CMD_DURATION является исключением по историческим причинам). Это правило не навязывается fish, но хорошая практика — использовать регистр для различения экспортируемых и неэкспортируемых переменных.
Fish также использует некоторые переменные внутри, обычно начинающиеся с __fish. Это внутренние переменные, и их обычно не нужно изменять напрямую.
Переменная статуса
Всякий раз, когда процесс завершается, программе, которая его запустила (обычно оболочке), возвращается код завершения. Этот код завершения — целое число, которое указывает вызывающему приложению, как прошла выполнение команды. В общем случае, код завершения 0 означает, что команда выполнилась без проблем, а ненулевой код завершения означает, что возникла проблема.
Fish сохраняет код завершения последнего завершившегося процесса в переменной status.
Если fish сталкивается с проблемой при выполнении команды, переменная статуса также может быть установлена в определённое значение:
- 0 — обычно код завершения команд, если они успешно выполнили запрошенную операцию.
- 1 — обычно код завершения команд, если они не смогли выполнить запрошенную операцию.
- 121 — обычно код завершения команд, если им были переданы неверные аргументы.
- 123 означает, что команда не была выполнена, потому что имя команды содержало недопустимые символы.
- 124 означает, что команда не была выполнена, потому что ни один из шаблонов в команде не дал совпадений.
- 125 означает, что хотя исполняемый файл с указанным именем был найден, операционная система не смогла запустить команду.
- 126 означает, что хотя файл с указанным именем был найден, он не был исполняемым.
- 127 означает, что ни функция, ни встроенная команда, ни команда с заданным именем не были найдены.
Если процесс завершается по сигналу, код завершения будет равен 128 плюс номер сигнала.
Статус можно инвертировать с помощью not (или !), что полезно в условии. Это преобразует статус 0 в 1, а любой ненулевой статус в 0.
Также есть $pipestatus, который представляет собой список всех значений status процессов в цепочке команд. Отличие заключается в том, что not применяется к $status, но не к $pipestatus, так как теряется информация.
Например:
not cat file | grep -q fish echo status is: $status pipestatus is $pipestatus
Здесь $status отражает статус grep, который возвращает 0, если что-то найдено, отрицается not (т.е. 1, если найдено, 0 в противном случае). $pipestatus отражает статус cat (который возвращает ненулевое значение, например, когда файл не может быть найден) и grep, без инверсии.
Таким образом, если оба cat и grep выполнились успешно, $status будет 1 из-за not, а $pipestatus будет 0 и 0.
Первый процесс может завершиться неудачно, а второй — успешно. Один из распространённых примеров — когда вторая программа завершается слишком рано.
Например, если у вас есть цепочка команд:
cat file1 file2 | head -n 50
Это скажет cat напечатать два файла, “file1” и “file2”, один за другим, а head затем напечатает только первые 50 строк. В этом случае вы часто увидите такую последовательность:
> cat file1 file2 | head -n 50 # 50 lines of output > echo $pipestatus 141 0
Здесь «141» означает, что cat был убит сигналом номер 13 (128 + 13 == 141) — сигнал SIGPIPE. Вы также можете использовать fish_kill_signal, чтобы увидеть номер сигнала. Это происходит потому, что он всё ещё работал, а затем head закрыл канал, поэтому cat получил сигнал, который не игнорировал, и поэтому он умер.
Будет ли cat здесь видеть SIGPIPE, зависит от длины файла и того, сколько он записывает за раз, поэтому вы можете увидеть pipestatus «0 0», в зависимости от реализации. Это общая проблема Unix, а не проблема, специфичная для fish. Некоторые оболочки имеют функцию «pipefail», которая обозначит цепочку команд как неудачную, если один из процессов в ней завершился неудачно, и это большая проблема с ней.
Локальные переменные
«Локаль» программы — это набор языковых и региональных настроек, зависящих от языка и культурных традиций. В UNIX эти настройки состоят из нескольких категорий.
-
LANG -
Это типичная переменная среды для указания локали. Пользователь может задать эту переменную, чтобы указать язык, регион и кодировку символов. Фактические значения зависят от платформы, за исключением специальных значений, таких как
CилиPOSIX.Значение LANG используется для каждой категории, если не установлена переменная для этой категории или переменная LC_ALL. Поэтому, обычно, достаточно установить только LANG.
Пример значения:
en_US.UTF-8для американской версии английского языка и кодировки UTF-8 илиde_AT.UTF-8для австрийской версии немецкого языка и кодировки UTF-8. Ваша операционная система может иметь командуlocale, которую можно вызвать какlocale -a, чтобы увидеть список определенных локалей.Рекомендуется использовать кодировку UTF-8.
-
LC_ALL -
Переопределяет переменную среды
LANGи значения других переменныхLC_*. Если она установлена, другие переменные не используются.Обычно следует использовать другие переменные. Используйте LC_ALL только когда нужно переопределить что-либо.
-
LC_COLLATE -
Определяет правила эквивалентности регистров и алфавитного порядка (сортировка).
-
LC_CTYPE -
Определяет правила классификации, такие как тип символа (буква, цифра и т. д.). Самое важное, она определяет кодировку текста — какие числа соответствуют каким символам. В современных системах, обычно, это значение, заканчивающееся на «UTF-8».
-
LC_MESSAGES -
LC_MESSAGESопределяет язык, на котором отображаются сообщения.
-
LC_MONETARY -
Определяет валюту, её форматирование и используемые символы.
-
LC_NUMERIC -
Устанавливает локаль для форматирования чисел.
-
LC_TIME -
Устанавливает локаль для форматирования дат и времени.
Встроенные команды
Fish содержит ряд команд, непосредственно встроенных в оболочку. Мы называем их «встроенными». К ним относятся:
- Встроенные команды, которые изменяют состояние оболочки - cd изменяет директорию, set задаёт переменные
- Встроенные команды для работы с данными, такие как string для строк и math для чисел, count для подсчёта строк или аргументов, path для работы с путями
- status для запроса о состоянии оболочки
- printf и echo для создания вывода
- test для проверки условий
- argparse для парсинга аргументов функций
- source для чтения скрипта в текущей оболочке (изменения переменных сохраняются) и eval для выполнения строки как скрипта
- random для получения случайных чисел или выбора случайного элемента из списка
- read для чтения из канала или терминала
Для получения списка всех встроенных команд используйте builtin -n.
Для получения списка всех встроенных команд, функций и команд, поставляемых с fish, см. список команд. Документация также доступна с помощью ключа --help.
Поиск команд
Когда fish получает команду, она проходит несколько этапов для её поиска.
Если команда содержит /, fish пытается выполнить указанный файл, начиная с текущей директории.
Если команда не содержит /, это может быть функция, встроенная команда или внешняя команда, поэтому fish проходит полный поиск.
В порядке:
-
Она пытается разрешить её как функцию.
- Если функция уже известна, она используется
- Если существует файл с именем и расширением «.fish» в
fish_function_path, он загружается. (Если таких файлов несколько, используется только первый) - Если функция теперь определена, она используется
- Она пытается разрешить её как встроенную команду.
-
Она пытается найти исполняемый файл в
PATH.- Если файл найден, она сообщает ядру о запуске файла.
- Если ядро знает, как запустить файл (например, через
#!строку -#!/bin/shили#!/usr/bin/python), оно делает это. - Если ядро сообщает, что не может запустить файл из-за отсутствия интерпретатора, и файл проходит предварительную проверку, fish сообщает
/bin/shо запуске файла.
Если ни один из этих методов не работает, fish выполняет функцию fish_command_not_found и устанавливает status в 127.
Можно использовать type для отображения того, как fish разрешила команду:
> type --short --all echo echo is a builtin echo is /usr/bin/echo
Запрос пользовательского ввода
Иногда требуется запросить у пользователя ввод, например, для подтверждения чего-либо. Это можно сделать с помощью встроенной команды read.
Давайте рассмотрим пример. Эта функция будет искать файлы в всех директориях, которые она получает как аргументы, и если их больше пяти, она спросит пользователя, нужно ли их отображать, но только если она подключена к терминалу:
function show_files
# This will glob on all arguments. Any non-directories will be ignored.
set -l files $argv/*
# If there are more than 5 files
if test (count $files) -gt 5
# and both stdin (for reading input) and stdout (for writing the prompt)
# are terminals
and isatty stdin
and isatty stdout
# Keep asking until we get a valid response
while read --nchars 1 -l response --prompt-str="Are you sure? (y/n)"
or return 1 # if the read was aborted with ctrl-c/ctrl-d
switch $response
case y Y
echo Okay
# We break out of the while and go on with the function
break
case n N
# We return from the function without printing
echo Not showing
return 1
case '*'
# We go through the while loop and ask again
echo Not valid input
continue
end
end
end
# And now we print the files
printf '%s\n' $files
end
Если запустить эту функцию как show_files /, скорее всего, она будет спрашивать, пока пользователь не нажмёт Y/y или N/n. Если запустить как show_files / | cat, она выведет файлы без запроса. Если запустить как show_files ., возможно, она просто выведет что-то, не спрашивая, потому что файлов меньше пяти.
Имена переменных и функций оболочки
Имена переменных и функций (так называемые «идентификаторы») должны соответствовать определённым правилам:
- Имя переменной не может быть пустым. Оно может содержать только буквы, цифры и символы нижнего подчеркивания. Оно может начинаться и заканчиваться любым из этих символов.
- Имя функции не может быть пустым. Оно не может начинаться с дефиса («-») и не может содержать слеш («/»). Все остальные символы, включая пробел, допустимы. Имя функции также не может совпадать с зарезервированным ключевым словом или встроенной командой, такой как
ifилиset. - Имя режима привязки (например,
bind -m abc ...) должно быть валидным именем переменной.
Другие вещи имеют другие ограничения. Например, допустимые имена файлов зависят от вашей системы, но, по крайней мере, они не могут содержать «/» (потому что это разделитель путей) или нулевой байт (потому что так UNIX завершает строки).
Файлы конфигурации
При запуске fish он считывает и выполняет файлы конфигурации. Местоположение этих файлов зависит от конфигурации сборки и переменных окружения.
Основной файл — ~/.config/fish/config.fish (или, точнее, $XDG_CONFIG_HOME/fish/config.fish).
Файлы конфигурации выполняются в следующем порядке:
-
Фрагменты конфигурации (называемые
*.fish) в каталогах:-
$__fish_config_dir/conf.d(по умолчанию~/.config/fish/conf.d/) -
$__fish_sysconf_dir/conf.d(по умолчанию/etc/fish/conf.d/) -
Каталоги для других программ, чтобы отправлять фрагменты конфигурации для своего программного обеспечения:
- каталоги в
$__fish_user_data_dir(обычно~/.local/share/fish, управляемые переменной окруженияXDG_DATA_HOME) - каталог
fish/vendor_conf.dв каталогах, перечисленных в$XDG_DATA_DIRS(по умолчанию/usr/share/fish/vendor_conf.dи/usr/local/share/fish/vendor_conf.d)
Эти каталоги также доступны в
$__fish_vendor_confdirs. Обратите внимание, что изменение этого в работающем fish не повлияет, так как к этому моменту каталоги уже были прочитаны. - каталоги в
Если в этих каталогах есть несколько файлов с одинаковым именем, выполнится только первый. Они выполняются в порядке их имени файла, отсортированного (как в шаблонах) в естественном порядке (например, «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 также поставляется файл __fish_build_paths.fish. Он может быть настроен во время сборки, например, потому что вашей системе требуются специальные пути.
Флаги будущих функций
Флаги будущих функций — это способ fish разрабатывать изменения, которые могут сломать скрипты. Нарушающие изменения вводятся как опции по умолчанию, в нескольких выпусках они становятся опциями по умолчанию, а в конечном итоге старое поведение удаляется.
Вы можете увидеть текущий список функций с помощью status features:
> status features stderr-nocaret on 3.0 ^ no longer redirects stderr qmark-noglob off 3.0 ? no longer globs regex-easyesc on 3.1 string replace -r needs fewer \\'s ampersand-nobg-in-token on 3.4 & only backgrounds if followed by a separating character
Вот что они означают:
-
stderr-nocaretбыл представлен в fish 3.0 (и стал значением по умолчанию в 3.3). Он делает^обычным символом вместо обозначения перенаправления stderr, чтобы упростить работу с кавычками и т. п. Используйте2>вместо этого. Это больше нельзя отключить начиная с fish 3.5. Флаг все еще можно проверить на совместимость, но значениеno-stderr-nocaretпросто будет проигнорировано. -
qmark-noglobтакже был представлен в fish 3.0. Он делает?обычным символом вместо одиночного символьного шаблона. Используйте*вместо него (что соответствует нескольким символам) или найдите другие способы сопоставления файлов, например,find. -
regex-easyescбыл представлен в 3.1. Он делает так, что выражение замены вstring replace -rвыполняет на одну итерацию меньше экранирования. Раньше, чтобы экранировать обратную косую черту, нужно было использоватьstring replace -ra '([ab])' '\\\\\\\\$1'. Теперь достаточно'\\\\$1'. Проверьте свои вызовыstring replace, если вы используете это где-либо. -
ampersand-nobg-in-tokenбыл представлен в fish 3.4. Он делает так, что&больше не интерпретируется как оператор фонового выполнения в середине токена, что упрощает работу с URL-адресами. Поместите пробелы или точку с запятой после&. Такое форматирование всё равно рекомендуется, иfish_indentуже сделало это за вас.
Эти изменения включены по умолчанию. Они могут быть включены на сеансовом уровне:
> fish --features qmark-noglob,regex-easyesc
или включены глобально для пользователя:
> set -U fish_features regex-easyesc qmark-noglob
Функции будут установлены только при запуске, поэтому эта переменная вступит в силу только если она универсальна или экспортирована.
Вы также можете использовать версию как группу, поэтому 3.0 эквивалентно «stderr-nocaret» и «qmark-noglob». Вместо версии специальная группа all включает все функции.
Префикс функции no- отключает ее вместо этого. Например, чтобы снова включить ? - одиночный символ шаблона:
set -Ua fish_features no-qmark-noglob
В настоящее время по умолчанию включены следующие функции:
- stderr-nocaret -
^больше не перенаправляет stderr, используйте2>. Включено по умолчанию в fish 3.3.0. Больше не изменяемо начиная с fish 3.5.0. - regex-easyesc -
string replace -rтребует меньше обратных косых черт в части замены. Включено по умолчанию в fish 3.5.0. - ampersand-nobg-in-token -
&в середине слова — это обычный символ, а не фоновое выполнение. Включено по умолчанию в fish 3.5.0.
Обработчики событий
При определении новой функции в fish её можно сделать обработчиком событий, то есть функцией, которая автоматически выполняется при наступлении определённого события. События, которые могут вызвать обработчик, в настоящее время следующие:
- При получении сигнала
- При завершении процесса
- При обновлении значения переменной
- При отображении приглашения
Пример:
Чтобы указать обработчик сигнала для сигнала WINCH, напишите:
function my_signal_handler --on-signal WINCH
echo Got WINCH signal!
end
Fish уже имеет следующие именованные события для переключателя --on-event:
-
fish_promptгенерируется всякий раз, когда отображается новое приглашение fish. -
fish_preexecгенерируется непосредственно перед выполнением интерактивной команды. Строка команды передается в качестве первого параметра. Не генерируется, если команда пустая. -
fish_posterrorгенерируется сразу после выполнения команды с синтаксическими ошибками. Строка команды передается в качестве первого параметра. -
fish_postexecгенерируется непосредственно после выполнения интерактивной команды. Строка команды передается в качестве первого параметра. Не генерируется, если команда пустая. -
fish_exitгенерируется непосредственно перед выходом fish. -
fish_cancelгенерируется при очистке строки команд.
События могут быть вызваны командой emit, и не обязательно определяться предварительно. Имена должны просто совпадать. Например:
function handler --on-event imdone
echo generator is done $argv
end
function generator
sleep 1
# The "imdone" is the name of the event
# the rest is the arguments to pass to the handler
emit imdone with $argv
end
Если для события существует несколько обработчиков, все они будут выполнены, но порядок может меняться между выпусками fish, поэтому вы не должны на него полагаться.
Обратите внимание, что обработчики событий активируются только при загрузке функции, что означает, что вам нужно иначе source или выполнить функцию вместо того, чтобы полагаться на автозагрузку. Один из подходов — поместить его в ваш файл конфигурации.
Дополнительную информацию о том, как определить новые обработчики событий, см. в документации к команде function.
Отладка скриптов fish
Fish включает базовые встроенные средства отладки, которые позволяют приостановить выполнение скрипта в произвольной точке. При этом вам будет представлено интерактивное приглашение, где вы можете выполнить любую команду fish для проверки или изменения состояния (собственно команд отладки нет). Например, вы можете проверить или изменить значение любой переменной с помощью printf и set. Также вы можете запустить status print-stack-trace, чтобы увидеть, как была достигнута текущая точка останова. Чтобы продолжить нормальное выполнение скрипта, просто введите exit или Control+D.
Чтобы начать сеанс отладки, просто вставьте встроенную команду breakpoint в той части функции или скрипта, где вы хотите получить контроль, а затем запустите функцию или скрипт. Кроме того, стандартное действие сигнала TRAP — вызов этой встроенной команды, что означает, что работающий скрипт можно активно отлаживать, отправив ему сигнал TRAP (kill -s TRAP <PID>). Поддержка интерактивного установки или изменения точек останова из этого приглашения отладки ограничена: возможно вставить новые точки останова в (или удалить старые из) других функций, используя функцию funced для редактирования определения функции, но невозможно добавить или удалить точку останова из функции/скрипта, которые в данный момент загружены и выполняются.
Другой способ отладить проблемы со скриптом — установить переменную fish_trace, например, fish_trace=1 fish_prompt, чтобы увидеть, какие команды выполняет fish при запуске функции fish_prompt.
Если вы хотите специально отладить проблемы с производительностью, fish можно запустить с опцией --profile /path/to/profile.log для сохранения профиля в указанном пути. Этот журнал профиля включает разбивку того, сколько времени занял каждый этап выполнения. См. fish для получения дополнительной информации.
© 2005-2009 Axel Liljencrantz, 2009-2023 fish-shell contributors
Licensed under the GNU General Public License, version 2.
https://fishshell.com/docs/3.7/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Нет многострочных комментариев. Если вы хотите, чтобы комментарий занимал несколько строк, просто начинайте каждую строку с
#.Комментарии также могут появляться после строки, как в этом примере: