Язык fish
Данный документ представляет собой исчерпывающий обзор скриптового языка fish.
Для интерактивных функций см. Интерактивное использование.
Обзор синтаксиса
Оболочки, такие как fish, используются путём ввода команд. Команда выполняется, путём ввода имени команды, за которым следуют любые аргументы. Например:
echo hello world
Это вызывает команду echo. 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представляет символ escape. -
\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— буква алфавита, представляет управляющую последовательность, генерируемую нажатием клавиши Ctrl и указанной буквой. Например,\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 нет отдельного понятия «псевдонима», мы просто используем это слово для функциональной обертки такого типа.
Для альтернативы попробуйте сокращения. Это слова, которые расширяются во время ввода, а не являются фактическими функциями внутри оболочки.
Автозагрузка функций
Функции могут быть определены в командной строке или в файле конфигурации, но они также могут быть загружены автоматически. Это имеет некоторые преимущества:
- Автоматически загруженная функция становится доступной для всех запущенных оболочек.
- Если определение функции изменено, все запущенные оболочки автоматически перезагрузят изменённую версию, через некоторое время.
- Время запуска и использование памяти улучшаются и т. д.
Когда программе 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). - Директории для других программ, чтобы размещать свои функции. Они находятся в директориях переменной среды
XDG_DATA_DIRS, в поддиректорииfish/vendor_functions.d. По умолчанию это обычно/usr/share/fish/vendor_functions.dи/usr/local/share/fish/vendor_functions.d. - Функции, поставляемые с fish, обычно установленные в
/usr/share/fish/functions(на самом деле$__fish_data_dir/functions).
Если вы не уверены, ваши функции, вероятно, должны находиться в ~/.config/fish/functions.
Как мы уже объясняли, файлы autoload загружаются по имени, поэтому, хотя вы можете поместить несколько функций в один файл, файл будет загружен автоматически только при попытке выполнить функцию с тем же именем.
Автозагрузка также не будет работать для обработчиков событий обработчиков событий, так как fish не может знать, что функция должна быть выполнена при возникновении события, если сама функция ещё не загружена. Для получения дополнительной информации см. раздел о обработчиках событий.
Если файл с правильным именем не определяет функцию, fish не будет читать другие файлы autoload, а вместо этого продолжит попытки использовать встроенные команды и, наконец, команды. Это позволяет маскировать функции, определённые позже в $fish_function_path, например, если ваш администратор поместил что-то в /etc/fish/functions, что вы хотите пропустить.
Если вы разрабатываете другую программу и хотите установить в ней функции fish, установите их в директорию функций «vendor». Поскольку этот путь различается в зависимости от системы, вы можете использовать pkgconfig для его определения, используя вывод pkg-config --variable functionsdir fish. Ваша система установки должна поддерживать пользовательский путь для переопределения пути pkgconfig, так как другим дистрибутивам может потребоваться легко его изменить.
Комментарии
Всё после # до конца строки является комментарием. Это значит, что он предназначен только для читателя; fish его игнорирует.
Это полезно для объяснения того, что и почему вы делаете:
function ls
# The function is called ls,
# so we have to explicitly call `command ls` to avoid calling ourselves.
command ls --color=auto $argv
end
Нет многострочных комментариев. Если вам нужно создать комментарий, занимающий несколько строк, просто начинайте каждую строку с #.
Комментарии также могут появляться после строки, как показано ниже:
set -gx EDITOR emacs # I don't like vim.
Условные операторы
Fish имеет некоторые встроенные команды, которые позволяют выполнять команды только в том случае, если выполняется определённое условие: if, switch, and и or, а также знакомый синтаксис &&/||.
Команда switch используется для выполнения одного из, возможно, многих блоков команд в зависимости от значения строки. Для получения дополнительной информации см. документацию по switch.
Другие условные операторы используют код возврата команды для принятия решения о том, должна ли выполняться команда или блок команд.
В отличие от языков программирования, которые вам могут быть знакомы, команда if не принимает условие, а принимает команду. Если эта команда возвращает успешный код возврата (то есть 0), то выполняется ветка if, иначе — ветка else.
Примеры:
# 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 значительно превышают это ограничение. Это мера, чтобы предотвратить зависание оболочки из-за бесполезных вычислений.
Подстановочные знаки ("Globbing")
Когда параметр содержит неуказанный подстановочный знак звёздочка или знак вопроса, fish использует его как подстановочный символ для сопоставления файлов.
-
*соответствует любому числу символов (включая ноль) в имени файла, кроме/. -
**соответствует любому числу символов (включая ноль), а также спускается в подкаталоги. Если**является отдельным сегментом, этот сегмент может соответствовать нулю раз для совместимости с другими оболочками. -
?может соответствовать любому одиночному символу, кроме/. Это устарело и может быть отключено через флагqmark-noglobфункциональных возможностей, так что?будет обычным символом.
Другие оболочки, такие как zsh, имеют более богатый синтаксис подстановочных знаков, например, **(.) для соответствия только обычным файлам. Fish этого не делает. Вместо того, чтобы изобретать велосипед, используйте программы, такие как find, чтобы искать файлы. Например:
function ff --description 'Like ** but only returns plain files.'
# This also ignores .git directories.
find . \( -name .git -type d -prune \) -o -type f | \
sed -n -e '/^\.\/\.git$/n' -e 's/^\.\///p'
end
Затем вы используете его вместо ** вот так, my_prog (ff), чтобы передать только обычные файлы в или ниже $PWD команде my_prog. 3
Сопоставления с подстановочными знаками сортируются без учёта регистра. При сортировке совпадений, содержащих числа, они сортируются естественным образом, так что строки '1' '5' и '12' будут отсортированы как 1, 5, 12.
Скрытые файлы (имена которых начинаются с точки) не учитываются при использовании подстановочных знаков, если в строке подстановочных знаков нет точки в соответствующем месте.
Примеры:
-
a*соответствует любому файлу, начинающемуся с буквы «a», в текущей директории. -
???соответствует любому файлу в текущей директории, имя которого состоит ровно из трёх символов. -
**соответствует всем файлам и директориям в текущей директории и во всех её поддиректориях. -
~/.*соответствует всем скрытым файлам (также известным как «dotfiles») и директориям в вашем домашнем каталоге.
Для большинства команд, если какой-либо шаблон не расширяется, команда не выполняется, $status устанавливается в ненулевое значение, и выводится предупреждение. Это поведение похоже на то, что делает bash с shopt -s failglob. Существует ровно 4 исключения, а именно set, перезаписывающие переменные в overrides, 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
-
3 -
Технически, unix допускает имена файлов с символами новой строки, и это разделяет выходные данные
findпо символам новой строки. Если вы хотите этого избежать, используйте опцию find's-print0и string split0.
Расширение переменных
Одним из самых важных расширений в 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"), переменные всегда расширяются ровно до одного аргумента. Если они пустые или не определены, это приводит к пустой строке. Если у них один элемент, они расширяются до этого элемента. Если у них более одного элемента, элементы объединяются пробелами, если переменная не является переменной пути - в этом случае будет использоваться двоеточие (:) вместо 4.
За пределами двойных кавычек переменные будут расширяться до такого количества аргументов, сколько в них элементов. Это означает, что пустой список расширится до ничего, переменная с одним элементом расширится до этого элемента, а переменная с несколькими элементами расширится до каждого из этих элементов по отдельности.
Если переменная расширяется до ничего, она отменяет любые другие присоединенные к ней строки. Дополнительную информацию см. в разделе декартовом произведении.
Символ $ также может использоваться несколько раз, как оператор "разрешения" (аналог * в 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][5] (взять первый элемент $foo, использовать его в качестве имени переменной, а затем получить пятый элемент этого).
-
4 -
В отличие от bash или zsh, которые будут объединяться с первой буквой $IFS (которая обычно является пробелом).
Подстановка команд
Выходные данные команды (или целой конвейерной системы) могут использоваться в качестве аргументов другой команде.
Когда вы пишете команду в скобках, например outercommand (innercommand), innercommand будет выполнена первой. Ее вывод будет взят, и каждая строка будет выдана как отдельный аргумент команде outercommand, которая затем будет выполнена. 5
Если вывод направлен на разделение строк или разделение строк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. begin; set -l IFS; set data (cat data.txt); end # Set ``$data`` to the contents of data, splitting on NUL-bytes. set data (cat data | string split0)
Иногда вы хотите передать вывод команды другой команде, которая принимает только файлы. Если это всего один файл, вы обычно можете просто передать его через конвейер, например:
grep fish myanimallist1 | wc -l
но если вам нужно несколько файлов или команда не считывает со стандартного ввода, "подстановка процесса" полезна. Другие оболочки 6 разрешают это с помощью foo <(bar) <(baz), а fish использует команду psub:
# Compare just the lines containing "fish" in two files: diff -u (grep fish myanimallist1 | psub) (grep fish myanimallist2 | psub)
Это создает временный файл, сохраняет вывод команды в этом файле и выводит имя файла, чтобы он был передан внешней команде.
-
5 -
Установить
$IFSв пустое значение отключает разделение строк. Это устарело, используйте string split вместо этого. -
6 -
По крайней мере, Bash и Zsh, хотя это расширение POSIX
Расширение с фигурными скобками
Фигурные скобки могут использоваться для записи списков, разделенных запятыми. Каждый элемент будет расширяться в новый параметр, к которому прикреплена окружающая строка. Это полезно для экономии набора текста и для разделения имени переменной от окружающего текста.
Примеры:
> 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. - Локальные переменные специфичны для текущей сессии fish и связаны с определённым блоком команд, и автоматически удаляются, когда определённый блок выходит из области видимости. Блок команд — это ряд команд, который начинается с одной из команд
for,while,if,function,beginилиswitch, и заканчивается командойend.
Переменные могут быть явно установлены как универсальные с ключом -U или --universal, глобальные с ключом -g или --global, или локальные с ключом -l или --local. Правила области действия при создании или обновлении переменной:
- Когда область действия явно указана, она будет использована. Если переменная с тем же именем существует в другой области действия, эта переменная не будет изменена.
- Когда область действия не указана, но переменная с таким именем существует, будет изменена переменная с наименьшей областью действия. Область действия не изменится.
- В качестве специального случая, когда область действия не указана и не определена переменная, переменная будет принадлежать области действия выполняемой в данный момент *функции*. Это отличается от флага
--local, который сделал бы переменную локальной для текущего *блока*.
Может быть много переменных с одинаковым именем, но разными областями действия. Когда вы используете переменную, будет использоваться переменная с наименьшей областью действия с таким именем. Если существует локальная переменная, она будет использована вместо глобальной или универсальной переменной с тем же именем.
Пример:
Есть несколько возможных применений для разных областей действия.
Обычно внутри функций следует использовать локальную область действия:
function something
set -l file /path/to/my/file
if not test -e "$file"
set 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
Вот пример локальных и переменных, ограниченных функцией:
begin
# This is a nice local scope where all variables will die
set -l pirate 'There be treasure in them thar hills'
set captain Space, the final frontier
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.
Переопределение переменных для одной команды
Если вы хотите переопределить переменную для одной команды, вы можете использовать выражения "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] [ARGUMENTS...]"
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 с помощью --path и --unpath опций к set.
Специальные переменные
Вы можете изменить настройки fish, изменив значения определённых переменных.
-
PATH, список каталогов, в которых искать команды -
CDPATH, список каталогов, в которых встроенная команда cd ищет новый каталог. - Переменные локали
LANG,LC_ALL,LC_COLLATE,LC_CTYPE,LC_MESSAGES,LC_MONETARY,LC_NUMERICиLC_TIMEзадают языковой параметр для оболочки и подпрограмм. Более подробную информацию см. в разделе Переменные локали. - Несколько переменных, начинающихся с префиксов
fish_colorиfish_pager_color. Более подробную информацию см. в разделе Переменные для изменения цвета подсветки. -
fish_ambiguous_widthуправляет вычисленной шириной символов с неоднозначной шириной. Это должно быть установлено в 1, если ваша терминальная программа отображает эти символы как символы одинарной ширины (типичный случай), или 2, если двойной ширины. -
fish_emoji_widthуправляет тем, рассматривает ли fish эмодзи как символы шириной 2 ячейки или 1 ячейки. Это необходимо, потому что правильное значение изменилось с 1 на 2 в Unicode 9, и некоторые терминалы могут об этом не знать. Установите это значение, если вы видите графические артефакты, связанные с эмодзи (или другими «специальными» символами). Обычно оно определяется автоматически. -
FISH_DEBUGиFISH_DEBUG_OUTPUTуправляют тем, какой отладочный вывод генерирует fish, и куда его помещает, аналогично--debugи--debug-outputопциям. Эти значения должны быть заданы при запуске, например, черезFISH_DEBUG='reader*' FISH_DEBUG_OUTPUT=/tmp/fishlog fish. -
fish_escape_delay_msопределяет, как долго fish ожидает нажатия другой клавиши после получения последовательности escape, чтобы отличить нажатие клавиши escape от начала последовательности escape. Значение по умолчанию — 30 мс. Увеличение этого значения увеличивает задержку, но позволяет нажимать escape вместо alt для назначенных комбинаций alt+символ. Более подробную информацию см. в соответствующей главе документации bind. -
fish_greeting, приветственное сообщение, выводимое при запуске. Это печатает функция с тем же именем, которую можно переопределить для более сложных изменений (см. funced -
fish_handle_reflow, определяет, должен ли fish перерисовывать командную строку при изменении размера терминала. В терминалах, которые переформатируют текст, это следует отключить. Установите значение 1 для включения, любое другое значение — для отключения. -
fish_history, текущее имя сессии истории. Если установлено, все последующие команды в интерактивной сессии fish будут записываться в отдельный файл, идентифицируемый по значению переменной. Если не установлено, используется имя сессии по умолчанию «fish». Если установлено пустое значение, история не сохраняется на диск (но остаётся доступной в интерактивной сессии). -
fish_key_bindings, имя функции, которая настраивает сочетания клавиш для редактора командной строки. -
fish_trace, если установлено и не пустое, заставит fish выводить команды перед их выполнением, аналогичноset -xв bash. Отладочная информация выводится в путь, указанный опцией --debug-output fish (по умолчанию 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_pid, идентификатор процесса (PID) оболочки. -
history, список последних введённых команд. -
HOME, домашний каталог пользователя. Эту переменную можно изменить. -
hostname, имя хоста машины. -
IFS, внутренний разделитель полей, используемый для разделения слов с встроенной командой read. Установка его в пустую строку также отключит разделение строк в подстановке команд. Эту переменную можно изменить. -
last_pid, идентификатор процесса (PID) последнего фонового процесса. -
PWD, текущий рабочий каталог. -
pipestatus, список кодов завершения всех процессов, составляющих последнюю выполненную цепочку команд. См. код завершения. -
SHLVL, уровень вложенности оболочек. Fish увеличивает это значение в интерактивных оболочках, в противном случае он просто передаёт его дальше. -
status, код завершения последнего завершившегося фонового процесса. Если процесс был завершен сигналом, код завершения будет равен 128 плюс номер сигнала. -
status_generation, счётчик «поколения»$status. Он будет инкрементирован только при получении явного статуса от предыдущей команды. (Например, фоновые задачи не будут увеличивать его). -
USER, текущее имя пользователя. Эту переменную можно изменить. -
version, версия текущей выполняемой fish (также доступна какFISH_VERSIONдля обратной совместимости). -
fish_killring, список элементов в кольце kill fish.
Согласно соглашению, для экспортируемых переменных обычно используется верхний регистр, а для переменных, которые не экспортируются, — нижний. (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.
Локали
«Локаль» программы — это её набор языковых и региональных параметров. В UNIX есть несколько отдельных переменных для управления разными аспектами — LC_CTYPE определяет кодировку текста, а LC_TIME — формат времени.
Переменные локали: LANG, LC_ALL, LC_COLLATE, LC_CTYPE, LC_MESSAGES, LC_MONETARY, LC_NUMERIC и LC_TIME. Эти переменные работают следующим образом: LC_ALL устанавливает все аспекты локали заданному значению. Если установлена LC_ALL, все остальные переменные локали будут проигнорированы (обычно не рекомендуется!). Другие переменные LC_ устанавливают указанный аспект информации локали. LANG — это значение по умолчанию, оно будет использоваться, если ни одна из переменных LC_ не указана.
Наиболее распространённый способ установить локаль — использование команды, например, set -gx LANG en_GB.utf8, которая устанавливает текущую локаль на английский язык, используемый в Великобритании, с использованием кодировки UTF-8. Таким образом, любая программа, которой требуется другое значение, может легко переопределить только это и не прибегать к LC_ALL. Список доступных локалей в вашей системе можно получить с помощью locale -a.
Поскольку fish должен обрабатывать вывод, который может содержать многобайтовые символы (например, эмодзи), он попытается установить свою внутреннюю LC_CTYPE на значение, совместимое с UTF8, даже если заданный эффективный LC_CTYPE — «C» (значение по умолчанию). Это предотвращает проблемы, например, с именами файлов, предоставляемыми в подсказках автозаполнения, даже если пользователь запускал fish с LC_ALL=C. Чтобы отключить эту обработку, установите fish_allow_singlebyte_locale в «1».
Обзор встроенных команд
Fish включает в себя ряд команд, непосредственно встроенных в оболочку. Их называют «встроенными командами». К ним относятся:
- Встроенные команды для управления состоянием оболочки — cd для смены каталога, set для установки переменных
- Встроенные команды для обработки данных, такие как string для строк и math для чисел, count для подсчёта строк или аргументов
- status для получения информации о состоянии оболочки
- printf и echo для создания вывода
- test для проверки условий
- argparse для парсинга аргументов функций
- source для чтения скрипта в текущей оболочке (изменения переменных сохраняются) и eval для выполнения строки как скрипта
- random для получения случайных чисел или случайного элемента из списка
Список всех встроенных команд можно получить с помощью builtin -n.
Список всех встроенных команд, функций и команд, поставляемых с fish, см. в списке команд. Документация также доступна с помощью переключателя --help.
Имена переменных и функций оболочки
Имена переменных и функций (также называемые «идентификаторами») должны соответствовать определённым правилам:
- Имя переменной не может быть пустым. Оно может содержать только буквы, цифры и символы нижнего подчеркивания. Оно может начинаться и заканчиваться любым из этих символов.
- Имя функции не может быть пустым. Оно не может начинаться с тире («-») и не может содержать слеш («/»). Все остальные символы, включая пробел, допустимы.
- Имя режима привязки (например,
bind -m abc ...) должно быть допустимым именем переменной.
Другие элементы имеют другие ограничения. Например, то, что допускается для имён файлов, зависит от вашей системы, но как минимум они не могут содержать «/» (потому что это разделитель путей) или нулевой байт (потому что это способ завершения строк в UNIX).
Флаги будущих функций
Флаги функций — это способ изменения этапов работы программы, которые могут нарушить скрипты. Внедряемые изменения вносятся по принципу добровольного включения, в нескольких выпусках они становятся по умолчанию выключенными, а в конечном итоге старое поведение удаляется.
Текущий список функций можно увидеть с помощью status features:
> status features stderr-nocaret on 3.0 ^ no longer redirects stderr qmark-noglob off 3.0 ? no longer globs regex-easyesc off 3.1 string replace -r needs fewer \\'s
В fish 3.0 есть два критических изменения: символ ^ ^ больше не перенаправляет вывод stderr, и символ вопроса ? больше не является шаблоном.
В fish 3.1 есть одно критическое изменение: string replace -r выполняет избыточное экранирование замены, поэтому экранирование обратных слэшей будет выглядеть как string replace -ra '([ab])' '\\\\\\\$1' a. Этот флаг удаляет это, если он включен, поэтому достаточно '\\\\$1'.
Эти изменения по умолчанию выключены. Их можно включить на основе сеанса:
> fish --features qmark-noglob,stderr-nocaret
или включить глобально для пользователя:
> set -U fish_features stderr-nocaret qmark-noglob
Функции будут устанавливаться только при запуске, поэтому эта переменная вступит в силу только в случае её глобальной установки или экспорта.
Также можно использовать версию как группу, поэтому 3.0 эквивалентно «stderr-nocaret» и «qmark-noglob».
Представление функции с префиксом no- отключает её.
Обработчики событий
При определении новой функции в fish её можно сделать обработчиком событий, то есть функцией, которая автоматически выполняется при возникновении определённого события. В настоящее время события, которые могут активировать обработчик:
- При получении сигнала
- При завершении работы задания
- При обновлении значения переменной
- При отображении приглашения
Пример:
Чтобы указать обработчик сигнала для сигнала WINCH, напишите:
function my_signal_handler --on-signal WINCH
echo Got WINCH signal!
end
Обратите внимание, что обработчики событий становятся активными только при загрузке функции, что означает, что вам нужно выполнить source или выполнить функцию, а не полагаться на автозагрузку. Один из способов — поместить его в ваш конфигурационный файл.
Дополнительную информацию о том, как определить новые обработчики событий, см. в документации по команде function.
Отладка скриптов fish
Fish включает встроенную систему отладки. Отладчик позволяет приостановить выполнение скрипта в произвольной точке. В этом случае вам будет представлено интерактивное приглашение. На этом приглашении вы можете выполнить любую команду fish (специальных команд отладки нет). Например, вы можете проверить или изменить значение любых переменных с помощью printf и set. В качестве другого примера, вы можете запустить status print-stack-trace, чтобы увидеть, как был достигнут этот разрыв. Чтобы продолжить нормальное выполнение скрипта, просто введите exit или Control+D.
Чтобы начать сеанс отладки, просто запустите встроенную команду breakpoint в той точке функции или скрипта, где вы хотите получить контроль. Кроме того, по умолчанию действие сигнала TRAP заключается в вызове этой встроенной команды. Таким образом, запущенный скрипт можно отладить, отправив ему сигнал TRAP с помощью команды kill. После попадания в отладчик легко вставить новые точки останова с помощью функции funced для редактирования определения функции.
© 2021 fish-shell developers
Licensed under the GNU General Public License, version 2.
https://fishshell.com/docs/3.3/language.html