Fish для пользователей bash
Это краткое руководство для пользователей, знакомых с bash (или, в меньшей степени, другими оболочками, такими как zsh или ksh), которые хотят узнать, чем отличается fish. Fish намеренно несовместим с POSIX, и поэтому некоторые привычные вещи работают по-другому.
Многие вещи похожи — обе оболочки в основном расширяют командные строки для выполнения команд, имеют конвейеры, перенаправления, переменные, шаблоны подстановки, используют вывод команд различными способами. Данный документ призван быстро показать различия.
Подстановки команд
В fish подстановки команд записываются как $(command) или (command), но не как `command`.
Кроме того, они разделяются только по символам новой строки вместо $IFS. Если вам нужно разделить по чему-то другому, используйте string split, string split0 или string collect. Если эти команды используются в качестве последней в подстановке команды, созданные разделения сохраняются. Таким образом:
for i in (find . -print0 | string split0)
будет корректно обрабатывать все возможные имена файлов.
Переменные
Fish устанавливает и удаляет переменные с помощью set вместо VAR=VAL и различных отдельных встроенных команд, таких как declare и unset и export. set принимает опции для определения области действия и экспорта переменной:
# Define $PAGER global and exported, # so this is like ``export PAGER=less`` set -gx PAGER less # Define $alocalvariable only locally, # like ``local alocalvariable=foo`` set -l alocalvariable foo
или для удаления переменных:
set -e PAGER
VAR=VAL выражения доступны как переопределения среды:
PAGER=cat git log
Fish не выполняет разделение слов. После того, как переменной присвоено значение, это значение остается неизменным, поэтому двойные кавычки при расширении переменных не являются обязательными, как в bash. 1
Например, вот bash:
> foo="bar baz" > printf '"%s"\n' $foo # will print two lines, because we didn't double-quote, so the variable is split "bar" "baz"
А вот fish:
> set foo "bar baz" > printf '"%s"\n' $foo # foo was set as one element, so it will be passed as one element, so this is one line "bar baz"
Все переменные являются «массивами» (мы используем термин «списки»), и расширение переменной расширяется до всех её элементов, с каждым элементом как отдельным аргументом (как в bash’s "${var[@]}"):
> set var "foo bar" banana > printf %s\n $var foo bar banana
Можно выбрать отдельные элементы списка:
echo $list[5..7]
См. Переменные оболочки для получения дополнительной информации.
-
1 -
zsh также по умолчанию не выполняет разделение слов (опция SH_WORD_SPLIT управляет этим)
Шаблоны подстановки (глобы)
Fish поддерживает только * и ** шаблоны подстановки (и устаревший ? шаблон подстановки). Если шаблон подстановки не совпадает, команда завершается ошибкой (как в bash’s failglob) за исключением случаев, когда команда for, set или count, или шаблон подстановки используется с переопределением среды (VAR=* command), в этом случае он расширяется до пустой строки (как в bash’s nullglob опции).
Подстановка шаблонов не происходит над расширенными переменными, поэтому:
set foo "*" echo $foo
не будет соответствовать никаким файлам.
Нет опций для управления подстановкой шаблонов, поэтому она всегда ведет себя таким образом.
См. Шаблоны подстановки для получения дополнительной информации.
Кавычки
Fish имеет два стиля кавычек: "" и ''. Переменные расширяются в двойных кавычках, ничего не расширяется в одинарных кавычках.
Нет $'', вместо этого последовательности, которые бы преобразовывались, преобразуются без кавычек:
> echo a\nb a b
См. Кавычки для получения дополнительной информации.
Обработка строк
Fish не имеет ${foo%bar}, ${foo#bar} и ${foo/bar/baz}. Вместо этого обработка строк выполняется встроенной командой string.
Например, чтобы заменить «bar» на «baz»:
> string replace bar baz "bar luhrmann" baz luhrmann
Она также может разделять строки:
> string split "," "foo,bar" foo bar
Сопоставление с регулярными выражениями как замена grep:
> echo bababa | string match -r 'aba$' aba
Выравнивание строк до заданной ширины произвольными символами:
> string pad -c x -w 20 "foo" xxxxxxxxxxxxxxxxxfoo
Преобразование строк в нижний/верхний регистр:
> string lower Foo foo > string upper Foo FOO
повторение строк, обрезка строк, экранирование строк или вывод длины или ширины строки (в ячейках терминала).
Специальные переменные
Некоторые переменные bash и их аналоги в fish:
-
$*,$@,$1и так далее:$argv -
$?:$status -
$$:$fish_pid -
$#: Нет переменной, используйте вместо этогоcount $argv -
$!:$last_pid -
$0:status filename -
$-: В основномstatus is-interactiveиstatus is-login
Подстановка процессов
Вместо <(command) fish использует (command | psub). Нет эквивалента >(command).
Обратите внимание, что оба этих элемента являются конструкциями bash, и большинство вещей можно легко выразить без них. Например, вместо:
source (command | psub)
просто используйте:
command | source
так как встроенная команда source fish может читать из стандартного ввода.
Встроенные документы
Fish не имеет <<EOF встроенных документов. Вместо
cat <<EOF some string some more string EOF
используйте:
printf %s\n "some string" "some more string"
или:
echo "some string some more string" # or if you want the quotes on separate lines: echo "\ some string some more string\ "
Кавычки поддерживаются через новые строки.
Функция «встроенных документов» состоит в:
- Чтение/интерпретация строки со специальными правилами до терминатора. 2
- Запись полученной строки во временный файл.
- Запуск команды, к которой относится встроенный документ, со ссылкой на этот файл как на стандартный ввод.
Это означает, что это в основном то же самое, что просто чтение из конвейера, поэтому:
echo "foo" | cat
в основном то же самое, что и
cat <<EOF foo EOF
Точно так же, как и с встроенными документами, команда должна быть подготовлена к чтению из стандартного ввода. Иногда это требует использования специальных опций, часто задавая имя файла - включает их.
Например:
echo "xterm rxvt-unicode" | pacman --remove - # is the same as (the `-` makes pacman read arguments from stdin) pacman --remove xterm rxvt-unicode
и можно было бы записать в других оболочках как
# This "-" is still necessary, because the heredoc is *also* passed over stdin! pacman --remove - << EOF xterm rxvt-unicode EOF
Таким образом, встроенные документы — это просто незначительный синтаксический сахар, который вводит много специальных правил, поэтому fish не использует их. Конвейеры являются основополагающим понятием и проще, и лучше комбинируются.
-
2 -
Например, «EOF» — это просто соглашение, терминатор может быть любой строкой, например, «THISISTHEEND» также работает. Использование
<<-обрезает ведущие табуляцию символы (но не другие пробелы), поэтому вы можете отступать строки, но только табуляцией. Подстановки (переменные, команды) выполняются в встроенном документе по умолчанию, но не если терминатор находится в кавычках:cat << "EOF".
Тест (test, [, [[)
Fish имеет POSIX-совместимую встроенную команду test или [ . Нет [[, и test не принимает == как синоним для =. Однако она может сравнивать числа с плавающей точкой.
set -q можно использовать для определения, существует ли переменная или содержит ли она определенное количество элементов (set -q foo[2]).
Арифметическое расширение
Fish не имеет $((i+1)) арифметического расширения, вычисления обрабатываются командой math:
math $i + 1
В отличие от арифметики bash, она может обрабатывать числа с плавающей точкой:
> math 5 / 2 2.5
А также имеет некоторые функции, такие как для тригонометрии:
> math cos 2 x pi 1
Вы можете передавать аргументы в math отдельно, как выше, или в кавычках. Так как fish использует () скобки для подстановок команд, кавычки необходимы, если вы хотите использовать их в выражении:
> math '(5 + 2) * 4'
И * и x являются допустимыми способами записи умножения, но * необходимо заключить в кавычки, так как оно похоже на шаблон подстановки.
Подсказки
Fish не использует переменные $PS1, $PS2 и так далее. Вместо этого подсказка — это вывод функции fish_prompt, плюс функция fish_mode_prompt, если включен режим vi, и функция fish_right_prompt для правой подсказки.
В качестве примера, вот относительно простая подсказка bash:
# <$HOSTNAME> <$PWD in blue> <Prompt Sign in Yellow> <Rest in default light white> export PS1='\h\[\e[1;34m\]\w\[\e[m\] \[\e[1;32m\]\$\[\e[m\] '
и приблизительный эквивалент в fish:
function fish_prompt
set -l prompt_symbol '$'
fish_is_root_user; and set prompt_symbol '#'
echo -s (prompt_hostname) (set_color blue) (prompt_pwd) \
(set_color yellow) $prompt_symbol (set_color normal)
end
Это показывает несколько различий:
- Fish предоставляет set_color для форматирования текста. Он может использовать 16 именованных цветов, а также последовательности RGB (поэтому вы также можете использовать
set_color 5555FF) - Вместо введения специальных управляющих последовательностей, таких как
\hдля имени хоста, подсказка просто представляет собой функцию. Чтобы достичь эффекта\h, fish предоставляет вспомогательные функции, такие как prompt_hostname, которая выводит сокращённую версию имени хоста. - Fish предлагает другие вспомогательные функции для добавления элементов в подсказку, например, fish_vcs_prompt для отображения информации о системах управления версиями (git, mercurial, svn), и prompt_pwd для отображения сокращённой
$PWD(домашний каталог пользователя становится~и любые компоненты пути сокращаются).
По умолчанию приглашение достаточно функциональное, и его код можно прочитать с помощью type fish_prompt.
В Fish нет $PS2 для продолжения строк, вместо этого строки отступаются, чтобы показать, что команда не завершена.
Блоки и циклы
Конструкции блокирования в Fish выглядят немного иначе. Все они начинаются со слова, заканчиваются end и не имеют второго слова для начала:
for i in 1 2 3; do
echo $i
done
# becomes
for i in 1 2 3
echo $i
end
while true; do
echo Weeee
done
# becomes
while true
echo Weeeeeee
end
{
echo Hello
}
# becomes
begin
echo Hello
end
if true; then
echo Yes I am true
else
echo "How is true not true?"
fi
# becomes
if true
echo Yes I am true
else
echo "How is true not true?"
end
foo() {
echo foo
}
# becomes
function foo
echo foo
end
# (note that bash specifically allows the word "function" as an extension, but POSIX only specifies the form without, so it's more compatible to just use the form without)
В Fish нет until. Используйте while not или while !.
Подпроцессы
Bash имеет функцию «подпроцессы», где он запускает другой процесс оболочки для определенных задач. Этот процесс оболочки будет независимым, и, например, любые изменения, которые он внесёт в переменные, не будут видны в основной оболочке.
Это включает в себя:
# A list of commands in `()` parentheses
(foo; bar) | baz
# Both sides of a pipe
foo | while read -r bar; do
# This variable will not be visible outside of the while loop.
VAR=VAL
# This background process will not be, either
baz &
done
() подпроцессы часто путают с {} группировкой, которая не использует подпроцесс. Если вам просто нужно сгруппировать, в fish можно использовать begin; end:
(foo; bar) | baz
# when it should really have been:
{ foo; bar; } | baz
# becomes
begin; foo; bar; end | baz
Вывод будет выполняться в том же процессе, поэтому while read циклы могут устанавливать переменные вне этого процесса:
foo | while read bar
set -g VAR VAL
baz &
end
echo $VAR # will print VAL
jobs # will show "baz"
Подпроцессы также часто путают с подстановками команд, которые bash записывает как `command` или $(command), а fish записывает как $(command) или (command). Bash также использует подпроцессы для их реализации.
Изоляцию обычно можно достичь, просто ограничив область видимости переменных (с set -l ), но если вам действительно нужно выполнить код в новой среде оболочки, вы всегда можете явно использовать fish -c 'your code here'.
Встроенные команды и другие команды
Сейчас становится очевидным, что fish уделяет гораздо больше внимания своим встроенным командам и внешним командам, чем своей синтаксике. Поэтому вот некоторые полезные встроенные команды и их грубые эквиваленты в bash:
-
string - заменяет большинство преобразований строк (
${i%foo}и др.) и может использоваться вместоgrepиsedи т. п. -
math - заменяет
$((i + 1))арифметику и также может обрабатывать числа с плавающей запятой и некоторые простые функции (синус и т. д.). -
argparse - может обрабатывать разбор параметров скрипта, для чего bash, вероятно, использовал бы
getopt(zsh предоставляетzparseopts). -
count может использоваться для подсчёта элементов и, следовательно, заменяет
$#и может быть использован вместоwc. -
status предоставляет информацию о состоянии оболочки, например, если она интерактивная или какой текущий номер строки. Это заменяет
$-и$BASH_LINENOи другие переменные. -
seq(1)может быть использован как замена для{1..10}расширения диапазона. Если ваша ОС не поставляетseqfish включает в себя функцию-замену.
© 2022 fish-shell developers
Licensed under the GNU General Public License, version 2.
https://fishshell.com/docs/3.4/fish_for_bash_users.html