Spec-Zone.ru › Fish 3.5

Рыба для пользователей bash

Данный документ предоставляет краткое описание отличий Fish от bash (и, в меньшей степени, других оболочек, таких как zsh или ksh). 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
# this is word splitting
"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 с "${var[@]}") :

> set var "foo bar" banana
> printf %s\n $var
foo bar
banana

Можно выбрать конкретные элементы списка:

echo $list[5..7]

Аргументы для set являются обычными, поэтому вы также можете установить переменную в выходной результат команды:

# Set lines to all the lines in file, one element per line
set lines (cat file)

или сочетание литеральных значений и вывода:

> set numbers 1 2 3 (seq 5 8) 9
> printf '%s\n' $numbers
1
2
3
5
6
7
8
9

Символ = не нужен и не полезен с set - set foo = bar, так как он установит переменную «foo» в два значения: «=» и «bar». set foo=bar выведет ошибку.

Дополнительную информацию смотрите в разделе Переменные оболочки.

1

zsh также по умолчанию не выполняет разделение слов (опция SH_WORD_SPLIT управляет этим)

Шаблоны подстановки (globs)

Fish поддерживает только шаблоны подстановки * и ** (и устаревший шаблон ?) в качестве синтаксиса. Если шаблон подстановки не соответствует, то команда завершается ошибкой (как в bash с failglob) , если команда не является for, set или count, или шаблон подстановки используется с переопределением среды (VAR=* command), в этом случае он расширяется до пустой строки (как в bash с опцией 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).

Обратите внимание, что оба этих — bashisms, и большинство вещей можно легко выразить без них. Например, вместо:

source (command | psub)

используйте просто:

command | source

так как в fish команда source может читать из стандартного ввода.

Heredocs

В Fish нет <<EOF “heredocs”. Вместо

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\
"

Кавычки следуют через новые строки.

Функционал heredocs:

  1. Чтение/интерпретация строки с особыми правилами до терминатора. 2
  2. Запись полученной строки в временный файл.
  3. Запуск команды, к которой прикреплен heredoc, с этим файлом как стандартным вводом.

Это означает, что это по существу то же самое, что и чтение из конвейера, поэтому:

echo "foo" | cat

по существу то же самое, что и

cat <<EOF
foo
EOF

Так же как и с heredocs, команда должна быть готова читать из стандартного ввода. Иногда для этого требуются специальные опции, часто задавая имя файла - активирует его.

Например:

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 - the heredoc is *also* passed over stdin!
pacman --remove - << EOF
xterm
rxvt-unicode
EOF

Таким образом, heredocs — это просто небольшой синтаксический сахар, который вводит много специальных правил, поэтому 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 являются допустимыми способами записи умножения, но * нужно заключать в кавычки, так как оно выглядит как шаблон подстановки glob.

Подсказки

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>
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

# (bash allows the word "function",
#  but this is an extension)

В 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 will not be visible outside of the loop.
    VAR=VAL
    # This background process will not be, either
    baz &
done

Подпроцессы часто путают с {} группировкой, которая не использует подпроцесс. Когда вам просто нужно сгруппировать, вы можете использовать begin; end в fish:

(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} диапазонному расширению. Если ваша операционная система не поставляет seq, fish включает в себя функцию-замену.

© 2022 fish-shell developers
Licensed under the GNU General Public License, version 2.
https://fishshell.com/docs/3.5/fish_for_bash_users.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API