Spec-Zone.ru › Fish 3.7

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

Это краткое руководство для пользователей bash (или, в меньшей степени, других оболочек, таких как zsh или ksh), которые хотят узнать, чем отличается рыба. Рыба намеренно несовместима с POSIX, и поэтому некоторые привычные вещи работают иначе.

Многие вещи похожи — обе в основе своей расширяют командные строки для выполнения команд, имеют конвейеры, перенаправления, переменные, шаблоны, используют вывод команд различными способами. Этот документ призван быстро показать вам различия.

Подстановки команд

Рыба записывает подстановки команд как $(command) или (command), но не `command`.

Кроме того, она разделяет их только по символам новой строки вместо $IFS. Если вы хотите разделить по чему-то другому, используйте string split, string split0 или string collect. Если эти команды используются в качестве последней в подстановке команды, созданные разделители переносятся. Например:

for i in (find . -print0 | string split0)

правильно обработает все возможные имена файлов.

Переменные

Рыба устанавливает и удаляет переменные с помощью set вместо VAR=VAL и различных отдельных встроенных команд, таких как declare и unset и export. set принимает опции для определения области действия и экспортируемости переменной:

# Define $PAGER *g*lobal and e*x*ported,
# 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

Рыба не выполняет разбиение слов. После того, как переменной присвоено значение, это значение остается неизменным, поэтому двойные кавычки при расширении переменных не являются необходимостью, как в 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"

А вот и рыба:

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

Аргументы 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 управляет этим)

Шаблоны (глобы)

Рыба поддерживает только * и ** шаблоны (и устаревший ? шаблон) в качестве синтаксиса. Если шаблон не соответствует, команда завершается неудачно (как в bash’s failglob) если команда не for, set или count или шаблон используется с переопределением среды (VAR=* command), в этом случае он расширяется до ничего (как в bash’s nullglob опция).

Расширение шаблонов не происходит над расширенными переменными, поэтому:

set foo "*"
echo $foo

не будут соответствовать никаким файлам.

Нет опций для управления расширением шаблонов, поэтому оно всегда ведёт себя так.

См. Шаблоны для получения дополнительной информации.

Кавычки

В рыбе есть два стиля кавычек: "" и ''. Переменные расширяются в двойных кавычках, ничего не расширяется в одинарных кавычках.

Нет $'', вместо этого последовательности, которые бы преобразовали, преобразуются при отсутствии кавычек:

> echo a\nb
a
b

См. Кавычки для получения дополнительной информации.

Обработка строк

В рыбе нет ${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 и их ближайшие аналоги в рыбе:

  • $*, $@, $1 и так далее: $argv
  • $?: $status
  • $$: $fish_pid
  • $#: Нет переменной, вместо этого используйте count $argv
  • $!: $last_pid
  • $0: status filename
  • $-: В основном status is-interactive и status is-login

Подстановка процесса

Вместо <(command) рыба использует (command | psub). Нет эквивалента >(command).

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

source (command | psub)

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

command | source

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

Heredocs

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

[2]

Например, «EOF» — это всего лишь соглашение, терминатор может быть произвольной строкой, например, «THISISTHEEND» тоже работает. А использование <<- обрезает ведущие символы табуляции (но не другие пробелы), поэтому вы можете отступать строки, но только с помощью табуляций. Подстановки (переменные, команды) выполняются в heredoc по умолчанию, но не если терминатор находится в кавычках: cat << "EOF".

Тест (test, [, [[)

Рыба имеет совместимую с POSIX встроенную команду test или [ . Нет [[ и test не принимает == в качестве синонима =. Однако она может сравнивать числа с плавающей точкой.

set -q может использоваться для определения, существует ли переменная или имеет ли она определённое количество элементов (set -q foo[2]).

Арифметическое расширение

Рыба не имеет $((i+1)) арифметического расширения, вычисления обрабатываются командой math:

math $i + 1

В отличие от арифметики bash, она может обрабатывать числа с плавающей точкой:

> math 5 / 2
2.5

А также имеет некоторые функции, такие как тригонометрические:

> math cos 2 x pi
1

Вы можете передавать аргументы команде math отдельно, как показано выше, или в кавычках. Поскольку рыба использует () скобки для подстановок команд, для их использования в выражении нужны кавычки:

> 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>
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 включает в себя функцию-замену.

Другие возможности

Bash имеет set -x или set -o xtrace для вывода всех выполняемых команд. В fish это можно включить, установив fish_trace.

Или, если вашей целью является профилирование того, сколько времени занимает каждая строка скрипта, вы можете использовать fish --profile — см. страницу команды fish.

© 2005-2009 Axel Liljencrantz, 2009-2023 fish-shell contributors
Licensed under the GNU General Public License, version 2.
https://fishshell.com/docs/3.7/fish_for_bash_users.html

Spec-Zone.ru

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