Мне просто интересно, какая именно разница между
[[ $STRING != foo ]]
а также
[ $STRING != foo ]
кроме того, что последний соответствует posix, встречается в sh, а первый является расширением, найденным в bash.
Мне просто интересно, какая именно разница между
[[ $STRING != foo ]]
а также
[ $STRING != foo ]
кроме того, что последний соответствует posix, встречается в sh, а первый является расширением, найденным в bash.
Ответы:
Есть несколько отличий. На мой взгляд, некоторые из наиболее важных являются:
[
является встроенным в Баш и многих других современных оболочек. Встроенный [
аналогичен test
дополнительному требованию закрытия ]
. Встроенные функции [
и test
имитируют функциональность, /bin/[
а /bin/test
также их ограничения, чтобы сценарии были обратно совместимы. Оригинальные исполняемые файлы все еще существуют в основном для соответствия POSIX и обратной совместимости. Запуск команды type [
в Bash означает, что [
по умолчанию она интерпретируется как встроенная. (Примечание: which [
ищет только исполняемые файлы в PATH и эквивалентно type -p [
)[[
не так совместимо, оно не обязательно будет работать с тем, на что /bin/sh
указывает. Так же [[
как и более современный вариант Bash / Zsh / Ksh.[[
он встроен в оболочку и не имеет устаревших требований, вам не нужно беспокоиться о разбиении слов на основе переменной IFS, чтобы связываться с переменными, которые оцениваются как строка с пробелами. Следовательно, вам не нужно помещать переменную в двойные кавычки.По большей части, остальное - просто более приятный синтаксис. Чтобы увидеть больше различий, я рекомендую эту ссылку на ответ на часто задаваемый вопрос: В чем разница между test, [и [[? , На самом деле, если вы серьезно относитесь к написанию сценариев bash, я рекомендую прочитать всю вики , включая FAQ, Pitfalls и Guide. Раздел теста из раздела руководства также объясняет эти различия, и почему авторы считают, что [[
это лучший выбор, если вам не нужно беспокоиться о своей портативности. Основными причинами являются:
< >
с обратными слешами, чтобы они не оценивались как перенаправление ввода, которое может действительно испортить некоторые вещи, перезаписывая файлы. Это снова восходит к тому, чтобы [[
быть встроенным. Если [(test) - внешняя программа, оболочка должна будет сделать исключение в способе оценки <
и >
только в том случае, если она /bin/test
вызывается, что на самом деле не имеет смысла.Короче говоря:
[Баш строит
[[]] Ключевые слова bash
Ключевые слова: ключевые слова очень похожи на встроенные, но главное отличие заключается в том, что к ним применяются специальные правила синтаксического анализа. Например, [встроена в bash, а [[является ключевым словом bash. Они оба используются для тестирования, но, поскольку [[является ключевым словом, а не встроенным, оно имеет несколько специальных правил синтаксического анализа, которые делают его намного проще:
$ [ a < b ]
-bash: b: No such file or directory
$ [[ a < b ]]
Первый пример возвращает ошибку, потому что bash пытается перенаправить файл b в команду [a]. Второй пример на самом деле делает то, что вы ожидаете. Символ <больше не имеет специального значения оператора перенаправления файлов.
Источник: http://mywiki.wooledge.org/BashGuide/CommandsAndArguments
[
является командой оболочки POSIX; его не нужно встраивать. ]
это просто аргумент, который ищет эта команда, так что синтаксис сбалансирован. Команда является синонимом, за test
исключением того, что test
не ищет закрытие ]
.
Различия в поведении
Некоторые отличия в Bash 4.3.11:
Расширение POSIX против Bash:
[
это POSIX[[
расширение Bash¹, задокументированное по адресу: https://www.gnu.org/software/bash/manual/bash.html#Conditional-Constructsобычная команда против магии
[
это обычная команда со странным именем.
]
это просто аргумент, [
который не позволяет использовать другие аргументы.
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 < b ]]
: лексикографическое сравнение[ a \< b ]
То же, что и выше. \
требуется или же делает перенаправление как для любой другой команды. Расширение Bash.expr a \< b > /dev/null
: Эквивалент POSIX², см .: https://stackoverflow.com/questions/21294867/how-to-test-strings-for-lexicographic-less-than-or-equal-in-bash/52707989#52707989&&
а также ||
[[ a = a && b = b ]]
: правда, логично и[ a = a && b = b ]
: синтаксическая ошибка, &&
проанализированная как разделитель команд ANDcmd1 && cmd2
[ a = a -a b = b ]
: эквивалентно, но не рекомендуется POSIX³[ a = a ] && [ b = b ]
: POSIX и надежный аналог(
[[ (a = a || a = b) && a = b ]]
: ложный[ ( a = a ) ]
: синтаксическая ошибка, ()
интерпретируется как подоболочка[ \( a = a -o a = b \) -a a = b ]
: эквивалентно, но ()
не поддерживается POSIX{ [ a = a ] || [ a = b ]; } && [ a = b ]
POSIX эквивалент 5разделение слов и генерация имени файла при расширениях (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? ]]
: true, потому что он выполняет сопоставление с образцом ( * ? [
это волшебство). Не расширяется до файлов в текущем каталоге.[ ab = a? ]
: a?
glob расширяется. Так может быть true или false в зависимости от файлов в текущем каталоге.[ ab = a\? ]
: false, не глобальное расширение=
и ==
одинаковы в обоих [
и [[
, но ==
это расширение Bash.case ab in (a?) echo match; esac
: POSIX эквивалент[[ ab =~ 'ab?' ]]
: false 4 , теряет магию с''
[[ ab? =~ 'ab?' ]]
: правда=~
[[ ab =~ ab? ]]
: true, POSIX расширенное совпадение с регулярным выражением , ?
не расширяется[ a =~ a ]
: ошибка синтаксиса. Нет эквивалента Bash.printf 'ab\n' | grep -Eq 'ab?'
: Эквивалент POSIX (только однострочные данные)awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?'
: Эквивалент POSIX.Рекомендация : всегда используйте []
.
Есть POSIX-эквиваленты для каждой [[ ]]
конструкции, которую я видел.
Если вы используете [[ ]]
вас:
[
это обычная команда со странным именем, никакой особой семантики не требуется.¹ Вдохновленный эквивалентной [[...]]
конструкции в оболочке Korn
² но терпит неудачу для некоторых значений a
или b
(например, +
или index
) и выполняет числовое сравнение, если a
и b
выглядит как десятичные целые числа. expr "x$a" '<' "x$b"
работает вокруг обоих.
³, а также терпит неудачу для некоторых значений a
или b
как !
или (
.
4 в bash 3.2 и выше и при условии, что совместимость с bash 3.1 не включена (как с BASH_COMPAT=3.1
)
5 , хотя группировка (здесь с {...;}
командой группой вместо (...)
которой будет запускать ненужную подоболочку) не является необходимой , как ||
и &&
операторы оболочки (в отличие от ||
и &&
[[...]]
операторов или -o
/ -a
[
операторов) имеют одинаковый приоритет. Так [ a = a ] || [ a = b ] && [ a = b ]
было бы эквивалентно.
printf 'ab' | grep -Eq 'ab?'
внутри if [ … ]
?
if ( printf 'ab' | grep -Eq 'a' ); then echo 'a'; fi
. []
это команда , так же , как grep
. ()
Не может быть необходимо в этой команде я не уверен: я добавил его из-за |
, зависит от того, как Bash разбирает вещи. Если бы не было, |
я уверен, что вы можете написать просто if cmd arg arg; then
.
()
: stackoverflow.com/questions/8965509/…
Single Bracket ie []
- это оболочка POSIX, соответствующая условному выражению.
Double Brackets ie [[]]
- это расширенная (или расширенная) версия стандартной версии POSIX, это поддерживается bash и другими оболочками (zsh, ksh).
В Баше, для количественного сравнения мы используем eq
, ne
, lt
и gt
, с двойными скобками для сравнения мы можем использовать ==
, !=
, <,
и в >
буквальном смысле.
[
это синоним тестовой команды. Даже если он встроен в оболочку, он создает новый процесс.[[
это новая улучшенная версия, которая является ключевым словом, а не программой. например:
[ var1 lt var2] #works
[ var1 < var2] #error: var2 No such file or directory
[ var1 \< var2] #works with escape
[[ var1 < var2]] #works
if
оператора, см. Mywiki.wooledge.org/BashPitfalls#if_.5Bgrep_foo_myfile.5D