Рыба для пользователей 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 выведет ошибку.
См. Переменные оболочки для получения дополнительной информации.
Шаблоны (глобы)
Рыба поддерживает только * и ** шаблоны (и устаревший ? шаблон) в качестве синтаксиса. Если шаблон не соответствует, команда завершается неудачно (как в 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»:
- Считывает/интерпретирует строку со специальными правилами до терминатора. [2]
- Записывает результирующую строку во временный файл.
- Запускает команду, к которой прикреплён 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 — это действительно незначительный синтаксический сахар, который вводит множество специальных правил, поэтому рыба их не имеет. Конвейеры являются базовым концепцией и проще и удобнее для использования.
Например, «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