Я вижу, я могу сделать
$ [ -w /home/durrantm ] && echo "writable"
writable
или
$ test -w /home/durrantm && echo "writable"
writable
или
$ [[ -w /home/durrantm ]] && echo "writable"
writable
Мне нравится использовать третий синтаксис. Они эквивалентны во всех отношениях и для всех отрицательных и краевых случаев? Существуют ли различия в переносимости, например, между bash в Ubuntu и в OS X или более старыми / более новыми версиями bash, например, до / после 4.0, и они оба расширяют выражения одинаково?
shell
posix
test
portability
Майкл Даррант
источник
источник
[ … ]
против[[ … ]]
противtest …
, есть более полные ответы в этом основном дубликата вопроса .Ответы:
[
является синонимомtest
команды и является одновременно встроенной командой bash и отдельной командой. Но[[
является ключевым словом bash и работает только в некоторых версиях. Так что из соображений портативности вам лучше использовать один[]
илиtest
источник
[
встроен POSIX или Bash?test
и к ним[
. Если оболочка может выполнять оценку самостоятельно, это экономит процесс и делает его несколько быстрее, но результат должен быть таким же.[
, определяется ли POSIX поведение или нет, и поэтому максимально переносимо (что, по-моему, и есть смысл в этом вопросе, если я не ошибаюсь)[
и другоеtest
- POSIX . Кажется, не существует ни одного «рекомендованного», хотя единственное различие (?), Которое я могу заметить между ними, заключается в том, чтоtest
аргумент «не должен распознавать» - «[как разделитель, указывающий конец параметров]» (? - подразумевает, что » -» будет признан истекшим аргументов в пользу[
, которую я не могу на самом деле придумать хороший тестовый пример для так или иначе но я отвлекся использование которого будет IMO,...[
выглядит элегантно, ноtest
isclearly команда)Да, есть различия. Наиболее портативными являются
test
или[ ]
. Они оба являются частью спецификации POSIXtest
.if ... fi
Конструкция также определяется POSIX и должен быть полностью портативным.[[ ]]
Этоksh
функция , которая также присутствует в некоторых версияхbash
( все современные ), вzsh
и , возможно , в других , но не присутствует вsh
илиdash
или различных других простых оболочках.Таким образом, чтобы сделать ваши скрипты портативными, использовать
[ ]
,test
илиif ... fi
.источник
bash
иzsh
поддерживали[[
в течение очень долгого времени (bash
добавили его в конце 90-х,zsh
не позднее 2000 года, и я был бы удивлен, если бы в нем вообще не было поддержки), так что вы вряд ли встретите какую-либо версию без нее[[
. Обнаружение другой POSIX-совместимой оболочки (например,dash
) гораздо более вероятно.[[
заключается в том, что расширения параметров не нужно заключать в кавычки:[[-f $file]]
событие работает, если$file
содержит пробельные символы.[[ $a =~ ^reg.*exp.*$' ]]
Обратите внимание, что
[] && cmd
это не то же самое, чтоif .. fi
строительство.Иногда его поведение довольно похоже, и вы можете использовать
[] && cmd
вместоif .. fi
. Но только иногда. Если у вас есть более одной команды для выполнения, если условие или вам нужноif .. else .. fi
быть осторожным и прорабатывать логику.Пара примеров:
Это не то же самое, что
потому что, если
ls
не удастся,echo
будет выполнено, что не произойдет сif
.Другой пример:
это не то же самое, что
хотя эта конструкция будет действовать так же
пожалуйста, обратите внимание,
;
после того, как эхо важно и должно быть там.Таким образом, возобновив утверждение выше, мы можем сказать,
[] && cmd
== если первая команда успешна, выполнить следующуюif .. fi
== если условие (которое может быть и тестовой командой), затем выполнить команду (ы)Так что для переносимости
[
и[[
использования[
только.if
совместим с POSIX. Так что, если вам придется выбирать между[
иif
смотреть на вашу задачу и ожидаемое поведение.источник
[ -z "$VAR" ] && { ls file; true; } || echo wiiii
. Это немного более многословно, но все же короче, чемif...fi
конструкция.[
иif
как субтитры, но это не так. Это на самом деле,&&
что заменяетif
.[
выполняет некоторый код и возвращает статус, очень какls
иgrep
будет.if
выполнение ветвлений зависит от состояния возврата команды (оператора), заданного после if, это может быть любая команда (оператор).&&
выполняет следующий оператор, только если предыдущий вернул 0, очень похоже на простойif..then..fi
.На самом деле
&&
это заменяет оператор аif
, а неtest
:if
оператор в сценариях оболочки проверяет, вернула ли команда «успешный» (нулевой) статус выхода; в вашем примере команда есть[
.Итак, на самом деле есть две вещи, которые вы меняете здесь: команда, используемая для запуска теста, и синтаксис, используемый для выполнения кода, основанного на результате этого теста.
Тестовые команды:
test
является стандартизированной командой для оценки свойств строк и файлов; в вашем примере вы запускаете командуtest -w /home/durrantm
[
псевдоним этой команды, одинаково стандартизированный, который имеет обязательный последний аргумент]
, чтобы выглядеть как выражение в скобках; не обманывайте себя, это все же просто команда (вы можете даже обнаружить, что в вашей системе есть файл с именем/bin/[
)[[
является расширенной версией тестовой команды, встроенной в некоторые оболочки, но не являющейся частью того же стандарта POSIX; он включает в себя дополнительные опции, которые вы не используете здесьУсловные выражения:
&&
Оператор ( стандартизован здесь ) выполняет логическую операцию, путем оценки двух команд и возврата 0 (который представляет собой истинно) , если они оба возвращают 0; она будет оценивать вторую команду только в том случае, если первая вернула ноль, поэтому ее можно использовать как простую условнуюif ... then ... fi
Конструкция ( стандартизовано здесь ) использует тот же метод судить «правду», но позволяет получить список соединений операторов вthen
предложении, а не одной команды , обеспечиваемой с помощью&&
короткого замыкания, а также обеспечиваетelif
иelse
положение, которые трудно писать используя только&&
и||
. Обратите внимание, что вif
выражении нет скобок вокруг условия .Итак, нижеприведенные примеры одинаково переносимы и полностью эквивалентны визуализации вашего примера:
test -w /home/durrantm && echo "writable"
[ -w /home/durrantm ] && echo "writable"
if test -w /home/durrantm; then echo "writable"; fi
if [ -w /home/durrantm ]; then echo "writable"; fi
Хотя следующие также эквивалентны, но менее переносимы из-за нестандартного характера
[[
:[[ -w /home/durrantm ]] && echo "writable"
if [[ -w /home/durrantm ]]; then echo "writable"; fi
источник
Для переносимости используйте
test
/[
. Но если вам не нужна переносимость, ради здравомыслия вы и другие, читающие ваш сценарий, используете[[
. :)Также смотрите
What is the difference between test, [ and [[ ?
в BashFAQ .источник
Если вы хотите переносимости за пределы мира, похожего на Борн, то:
самый портативный. Работает как в снарядах Борна, так
csh
и вrc
семьях.результат будет
"writable"
вместоwritable
в оболочкахrc
семьи (rc
,es
,akanga
, где"
не специальный).не будет работать в оболочках
csh
илиrc
семейств в системах, в которых нет[
команды$PATH
(известно, что некоторые имеют,test
но не ее[
псевдоним).работает только в оболочках семьи Борн.
работает только в
ksh
(где он возник)zsh
иbash
(все 3 в семье Борн).Никто не будет работать в
fish
оболочке, где вам нужно:или:
источник
Моя самая важная причина для выбора либо
if foo; then bar; fi
илиfoo && bar
является ли статус завершения всей команды важно.Для сравнения:
с:
Вы можете подумать, что они делают то же самое; однако если
foo
произойдет сбой (или будет ложным, в зависимости от вашей точки зрения), то в первом примере do_baz не будет выполнен, так как сценарий завершится ... Командаset -e
дает команду оболочке немедленно выйти, если какая-либо команда вернет ложное состояние. Очень полезно, если вы делаете такие вещи, как:Вы не хотите, чтобы скрипт продолжал работать, если
cd
по какой-либо причине произошел сбой.источник
foo
не прервет сценарий в любом случае. Это особый случай дляset -e
(когда команда оценивается как условие (слева от некоторых && / || или в условиях if / while / before / elsif ...). Вbar
обоих случаях сбой приведет к выходу из оболочки.cd /some/directory && rm -rf -- *
илиcd /some/directory || exit; rm -rf -- *
(все еще не удаляет скрытые файлы). Мне лично не нравится идея использоватьset -e
в качестве предлога, чтобы не пытаться написать правильный код.