Различия в поведении
Некоторые отличия в Bash 4.3.11:
POSIX против расширения Bash:
обычная команда против магии
[
- это обычная команда со странным именем.
]
- это просто аргумент [
, который не позволяет использовать дополнительные аргументы.
Ubuntu 16.04 на самом деле имеет исполняемый файл для него /usr/bin/[
, предоставляемый coreutils, но встроенная версия bash имеет преимущество.
Ничто не изменяется в том, как Bash анализирует команду.
В частности, <
- это перенаправление, &&
и ||
объединяют несколько команд, ( )
генерирует подоболочки, если не экранировано \
, и расширение слова происходит как обычно.
[[ X ]]
- это единственная конструкция, которая делает магический анализ X
. <
, &&
, ||
и ()
обрабатываются специально, и правила разбиения слов различны.
Существуют и другие различия, такие как =
и =~
.
В Bashese: [
- встроенная команда, а [[
- ключевое слово: https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword
<
&&
и ||
[[ a = a && b = b ]]
: истина, логика и
[ a = a && b = b ]
: синтаксическая ошибка, &&
проанализирована как разделитель команд AND cmd1 && cmd2
[ a = a -a b = b ]
: эквивалентно, но устарело в POSIX³
[ a = a ] && [ b = b ]
: POSIX и надежный эквивалент
(
[[ (a = a || a = b) && a = b ]]
: false
[ ( a = a ) ]
: синтаксическая ошибка, ()
интерпретируется как подоболочка
[ \( a = a -o a = b \) -a a = b ]
: эквивалентно, но ()
устарело в POSIX
{ [ a = a ] || [ a = b ]; } && [ a = b ]
POSIX эквивалент⁵
разбиение слов и генерация имени файла при расширениях (split + glob)
x='a b'; [[ $x = 'a b' ]]
: правда, кавычки не нужны
x='a b'; [ $x = 'a b' ]
: синтаксическая ошибка, расширяется до [ a b = 'a b' ]
x='*'; [ $x = 'a b' ]
: синтаксическая ошибка, если в текущем каталоге более одного файла.
x='a b'; [ "$x" = 'a b' ]
: эквивалент POSIX
=
[[ ab = a? ]]
: верно, потому что оно соответствует шаблону (* ? [
- магия). Не расширяется до файлов в текущем каталоге.
[ ab = a? ]
: a?
шар расширяется. Так что может быть true или false в зависимости от файлов в текущем каталоге.
[ ab = a\? ]
: ложь, не глобальное расширение
=
и ==
одинаковы в [
и [[
, но ==
является расширением Bash.
case ab in (a?) echo match; esac
: эквивалент POSIX
[[ ab =~ 'ab?' ]]
: ложь⁴, теряет магию с ''
[[ ab? =~ 'ab?' ]]
: правда
=~
[[ ab =~ ab? ]]
: true, POSIX расширенное регулярное выражение match, ?
не расширяется
[ a =~ a ]
: синтаксическая ошибка. Нет эквивалента Bash.
printf 'ab\n' | grep -Eq 'ab?'
: эквивалент POSIX (только однострочные данные)
awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?'
: эквивалент POSIX.
Рекомендация : всегда используйте []
.
Есть эквиваленты POSIX для каждой [[ ]]
конструкции, которую я видел.
Если вы используете [[ ]]
, вы:
- потерять переносимость
- заставляет читателя изучать тонкости другого расширения bash.
[
- это обычная команда со странным именем, никакой особой семантики здесь не существует.
¹ Вдохновленный эквивалентной [[...]]
конструкцией в оболочке Korn
², но не для некоторых значений a
или b
(например, +
или index
) и выполняет числовое сравнение, если a
и b
выглядят как десятичные целые числа. expr "x$a" '<' "x$b"
работает вокруг обоих.
³, а также не работает для некоторых значений a
или b
, таких как !
или (
.
⁴ в bash 3.2 и выше и при условии, что совместимость с bash 3.1 не включена (как с BASH_COMPAT=3.1
)
⁵ хотя группирование (здесь с группой команд {...;}
вместо (...)
, которая запускает ненужную подоболочку) не является необходимым, поскольку операторы оболочки ||
и &&
(в отличие от операторов оболочки Операторы ||
и &&
[[...]]
или операторы -o
/ -a
[
имеют одинаковый приоритет. Так что [ a = a ] || [ a = b ] && [ a = b ]
будет эквивалентно.