Тест или [или [[более портативен и между раковинами удара и между другими раковинами?

Я вижу, что могу сделать

$ [ -w /home/durrantm ] && echo "writable"
writable

или

$ test -w /home/durrantm && echo "writable"
writable

или

$ [[ -w /home/durrantm ]] && echo "writable"
writable

I like using the third syntax. Are they equivalent in all ways and fили all negative and edge cases? Are there any differences in pилиtability, e.g. between bash on Ubuntu and on OS X или older/newer bash versions, e.g. befилиe/after 4.0 and do they both expand expressions the same way?

42
Для [… ] против [[…]] против проверяют … , есть более полные ответы в этот главным образом двойной вопрос.
добавлено автор Valters Vingolds, источник
Для конкретного вопроса тестирования на writability файла см. также Как неагрессивно проверить на доступ для записи к файлу?
добавлено автор G-Man, источник
Есть высказывание: "нет никакого портативного кода, только закодируйте, который был перенесен". Мой совет относительно этого: Используйте наиболее удобочитаемую форму (вероятно [[...]]) и попробуйте ее на всех платформах, которые вы хотите поддержать. Там не полезен в затемнении ваших сценариев, таким образом, они работают на древних платформах что ни вы, ни ваше использование целевой аудитории. Это просто сделает ваш код трудно, чтобы прочитать, представить ненужные ошибки, и возможно даже проблемы безопасности (как он сделал для openssl).
добавлено автор Sam Gamoran, источник

7 ответы

Да, есть различия. Самые портативные тест или [] . Это оба часть POSIX test specification.

, если... fi конструкция также определенный POSIX и должно быть абсолютно портативным.

[[]] ksh особенность, которая также присутствует в некоторых версиях удар (все современные), в zsh и возможно в других, но не присутствует в sh или черта или различные другие более простые раковины.

Так, чтобы сделать ваши сценарии портативными, используйте [] , тест если... fi .

34
добавлено
Одной интересной особенностью [[ является тот параметр расширения don' t должны быть указаны: [[-f $file]] событие работает, если $file содержит пробельные символы.
добавлено автор Matt Enright, источник
@helpermethod также, встроенные регулярные выражения [[$a = ~ ^reg. *exp.* $ ']]
добавлено автор GnP, источник
Только, чтобы отметить, <�закодируйте> удар , и zsh поддержали [[ в течение очень долгого времени (, удар добавил его в конце 90-х, zsh не позднее, чем 2000 и I' d быть удивленным, испытало ли это когда-нибудь недостаток в поддержке), таким образом, вы вряд ли столкнетесь с версией любого без [[. Столкновение с различной POSIX-послушной раковиной (такой как черта ) намного более вероятно.
добавлено автор Luke Smith, источник

[ is synonym of the test command and it is simultaneously a bash builtin and separate command. But [[ is a bash keyword and works in some versions only. So for reasons of portability you are better off using single [] or test

[ -w "/home/durrantm" ] && echo "writable"
28
добавлено

Please note, that [] && cmd Не то же самое как if .. fi construction.

Sometimes its behaviour its pretty similar and you can use [] && cmd instead of if .. fi. But only sometimes. If you have more then one command to execute if condition or you need if .. else .. fi be careful and whatch the logic.

Несколько примеров:

[ -z "$VAR" ] && ls file || echo wiiii

Не то же самое как

if [ -z $VAR ] ; then
  ls file
else
  echo wiii
fi

потому что, если ls потерпит неудачу, , эхо будет выполнено, которого не произойдет с если .

Другой пример:

[ -z "$VAR" ] && ls file && echo wiii

Не то же самое как

if [ -z "$VAR" ] ; then
   ls file
   echo $wiii
fi

хотя это строительство будет действовать то же самое

[ -z "$VAR" ] && { ls file ; echo wiii ; }

пожалуйста, отметьте ; после того, как эхо важно и должно быть там.

Так возобновляя заявление выше мы можем сказать

[] && cmd == if first command is successful then execute the next one

if .. fi == if condition (which may be the test command as well) then execute command(s)

Таким образом для мобильности между [ и [[ использование [ только.

if is POSIX compatible. So if you have to choose between [ and if choose looking at your task and expected behaviour.

19
добавлено
Я downvoted, потому что a) это - главным образом, хороший ответ, но это - ответ на различный вопрос. b), которые вы представляете [ и , если как замены, но они - not' t. It' s на самом деле && that' s замена , если . [ выполняет некоторый код и возвращает статус, во многом как ls и grep был бы. , если казнь отделений в зависимости от статуса возврата команды (заявление), данное после, если, это могла бы быть какая-либо команда (заявление). && выполняет следующее заявление, только если предыдущий возвратился 0, во многом как простое если.. тогда.. fi .
добавлено автор GnP, источник
@rush you' право ре, я пропустил отредактировать историю там. Мои извинения. Как я сказал, это - главным образом, хороший ответ, таким образом, я исправил свой голос.
добавлено автор GnP, источник
I' m, вероятно, просто быть плотным, но I' m, не видя, чем различие было бы..., вы могли, пожалуйста, дать пример, где те два строительства дало бы различные результаты?
добавлено автор evilsoup, источник
@evilsoup, обновленный. Может быть I' m не лучший человек, который объясняет, хотя я надеюсь, что это будет ясно теперь.
добавлено автор agrublev, источник
@gnp, хорошо. a), пожалуйста, проверьте комментарий от Майкла. Есть короткое объяснение что первоначально был различный вопрос. Я просто оставил ответ для истории. b) ответ был главным образом о различии между &&.. || и , если.. еще.. fi .
добавлено автор agrublev, источник
Сделанный вопросом быть о [против [[против теста и не также, о если... fi против &&, чтобы заставить его быть ОДНИМ вопросом. К сожалению, выполнение, которое заставляет этот ответ казаться вне пункта. Извинения за то, что не был получен вопрос m руда, сосредоточенная первоначально ведомый к этому. Живой и (пробуют к) учатся.:)
добавлено автор ExpelledFromParadise, источник
Очень положительные стороны, порыв. Я предполагаю, что безопасная форма вашего 1-го примера была бы: [-z "$VAR"] && {ls файл; верный;} || повторяют wiiii . It' s немного больше многословный, но it' s еще короче, чем , если... fi строительство.
добавлено автор DirkGently, источник

It's actually the && that is replacing the if, not the test: an if statement in shell scripting tests whether a command returned a "successful" (zero) exit status; in your example, the command is [.

Так, есть на самом деле две вещи, которые вы изменяете здесь: команда раньше запускала тест, и синтаксис раньше выполнял код на основе результата того теста.

Испытательные команды:

  • test is a standardised command for evaluating properties of strings and files; in your example, you are running the command test -w /home/durrantm
  • [ is an alias of that command, equally standardised, which has a mandatory last argument of ] in order to look like a bracketed expression; don't be fooled, it's still just a command (you may even find that your system has a file called /bin/[)
  • [[ is an extended version of the test command built into some shells, but not part of the same POSIX standard; it includes extra options which you are not using here

Условные выражения:

  • The && operator (standardised here) performs a logical AND operation, by evaluating two commands and returning 0 (which represents true) if they both return 0; it will only evaluate the second command if the first one returned zero, so it can be used as a simple conditional
  • The if ... then ... fi construct (standardised here) uses the same method of judging "truth", but allows for a compound list of statements in the then clause, rather than the single command afforded by an && short-circuit, and provides elif and else clauses, which are hard to write using only && and ||. Note that there are no brackets around the condition in an if statement.

Так, следующее все одинаково портативные, и совершенно эквивалентные, изображения вашего примера:

  • 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
9
добавлено
Да я удалил если.... fi часть, чтобы заставить это быть 1 вопросом.
добавлено автор ExpelledFromParadise, источник

Если вы хотите мобильность вне подобного Границе мира, то:

test -w /home/durrantm && echo writable

является самым портативным. Это работает в раковинах Границы, csh и дистанционное управление семьи.

test -w /home/durrantm && echo "writable"

произвел бы "перезаписываемый" вместо , перезаписываемого в раковинах дистанционное управление семья ( дистанционное управление , es , akanga , где " не особенный).

[ -w /home/durrantm ] && echo writable

не работал бы в раковинах csh или дистанционное управление семьи на системах, у которых нет [ командой в $PATH (некоторые, как было известно, имели тест , но не [ псевдоним).

if [ -w /home/durrantm ]; then echo writabe; fi

только работы в раковинах семьи Борна.

[[ -w /home/durrantm ]] && echo writable

только работы в ksh (где это произошло), zsh и удар (все 3 в семье Борна).

Ни один не работал бы в рыба раковина, где вам нужно:

[ -w /home/durrantm ]; and echo writable

или:

if [ -w /home/durrantm ]; echo writable; end
7
добавлено

Для мобильности используйте тест / [. Но если вам не нужна мобильность ради здравомыслия себя и других, читающих ваше использование сценария [[.:)

Также посмотрите то, Что различие между тестом, [и [[? в BashFAQ.

7
добавлено

My most important reason for choosing either if foo; then bar; fi or foo && bar is whether the exit status of the whole command is important.

сравните:

#!/bin/sh
set -e
foo && bar
do_baz

с:

#!/bin/sh
set -e
if foo; then bar; fi
do_baz

Вы могли бы думать, что они делают то же самое; однако, если foo потерпит неудачу (или ложное, в зависимости от вашей точки зрения), тогда в первом примере do_baz, то не будет выполнен, поскольку сценарий выйдет... устанавливает-e приказывает раковине немедленно выйти если любое возвращение команды ложный статус. Очень полезный, если вы делаете вещи как:

cd /some/directory
rm -rf *

Вы не хотите, чтобы сценарий продолжил бежать, если CD терпит неудачу по любой причине.

0
добавлено
Нет провальное foo не прервет сценарий ни в одном случае. That' s особый случай для устанавливает-e (когда команда оценена как условие (налево от некоторого && / || или в if/while/until/elsif... условия). Провальное бар вышло бы из раковины в обоих случаях.
добавлено автор Stéphane Chazelas, источник
Вы хотите CD / some/ справочник && комната-rf - * или CD / some/ справочник || выход; комната-rf - * (все еще doesn' t удаляют скрытые файлы). Я лично don' t как идея использовать набор-e как оправдание не приложить усилие, чтобы написать правильный код.
добавлено автор Stéphane Chazelas, источник