По-видимому, существует четыре возможных соединителя: &, &&, || и ;. Несмотря на то, что & коннектор мне понятен (он отправляет процесс в фоновый режим и оставляет терминал доступным), непонятно, в чем разница между && и ;. И я не знал о || до комментария Кайи.
Следующие вопросы касаются разницы между двумя соединителями, но в основном это делается в комментариях:
Когда вы должны их использовать соответственно? Было бы неплохо увидеть некоторые варианты использования: если я хочу запустить команду, а затем после ее завершения выключить компьютер, какой разъем мне следует выбрать?
Каковы их преимущества и опасности? Я Делаю Басак упоминания в комментарии к этот ответ что команда, подобная cd /somewhere_else; rm -Rf * может иметь разрушительные последствия, например, если первый элемент в цепочке команд выходит из строя.
A; B # Run A and then B, regardless of success of AA && B # Run B if and only if A succeededA || B # Run B if and only if A failedA & # Run A in background.
&& вторая команда выполняется только в том случае, если первая завершилась со статусом 0 (прошла успешно). ; выполняет обе команды, даже если первая завершается с ненулевым статусом.
Ваш пример с && может быть эквивалентно перефразировано как
if sudo apt-get update ; then sudo apt-get install pyrenamerfi
С помощью ; будет выполнять команды независимо от того, будет ли первая команда успешной или нет.
С помощью && будет выполняться вторая команда только тогда, когда первая команда выполнена успешно (статус 0).
Оба они используются с разных точек зрения. Например, для более длительного процесса, скажем, для установки вам нужно скомпилировать и установить его. вам следует make && make install. Таким образом, установка будет выполняться только в том случае, если make успешный.
Поэтому для зависимых команд вы должны использовать &&.
Wring bash или команды с независимыми командами, используйте ;.
Поэтому, если вы хотите выключить компьютер даже при сбое первого задания, используйте ; , но если хотите при полном успехе первого задания инициировать завершение работы, используйте &&.
a ; b будет выполняться b независимо от статуса выхода a. a && b будет выполняться b только в том случае, если a удалось выполнить.
Это необходимо и достаточно для ответа на первые 3 вопроса. В частности, 2 является слишком широким, и на него нельзя дать "один" окончательный ответ - лучше всего принимать решение в каждом конкретном случае.
В использовании ни того, ни другого нет никакой внутренней опасности. Опять же, приведенного выше определения достаточно. Это подразумевает, что вы напишете && когда b имеет непреднамеренные последствия, если a не удается. Имхо, нет необходимости в дополнительных правилах или объяснениях.
Ответ Джека это очень хорошее эмпирическое правило.
A; B # Run A and then B, regardless of success of AA && B # Run B if and only if A succeededA || B # Run B if and only if A failedA & # Run A in background.
Я бы добавил, что в некоторых случаях использование этих команд в подоболочке имеет смысл, когда мы хотим рассматривать их как единое целое или мы не хотим связывать результаты некоторых операций с текущей оболочкой.
Примеры:
Объединить выходные данные двух команд:
(ls foo; ls bar) > single-result.txt
Перейдите в каталог и выполните команду оттуда, не изменяя текущий каталог оболочки:
Честь и хвала Чит-лист Джека за то, что четко и лаконично объяснил, как это работает. Но все эти вещи имеют более общую причину для того, чтобы быть выбранными. Вам не нужно просто запоминать эти факты, когда вы делаете что-то в оболочке. Для получения более подробной информации вам также может быть интересно узнать, что:
; обычно используется в качестве разделителя операторов в таких языках, как C, C++, Perl, Java, C#, awk и множестве языков, которые были производными от них. Во всех этих случаях он выполняет одну и ту же функцию: делает одно, затем следующее. Это как точка в конце предложения.
& используется в C для побитового И так далее && был использован для логического И. Логически упорядочивание вещей в C включает в себя функцию, называемую сокращением. Короткое замыкание означает, что для И, если первое значение равно false, нет причин проверять второе значение. Один ложный элемент в И означает, что все это будет ложным. В оболочке это означает, что она не перейдет ко второй команде, если первая завершится неудачей. Или, если первое сработало, он перейдет ко второму, чтобы посмотреть, "может ли это быть ложным".
| используется в C для побитового ИЛИ около того || используется для логического ИЛИ. Логические ИЛИ также имеют функцию сокращения. В ИЛИ это означает, что вы ищете первую истинную вещь. Так что, если первое не удастся, он попробует второе.
Другие говорили об этом хорошо. С практической точки зрения я часто нахожу, что если вы хотите связать команды в цепочку, то вам также хотелось бы знать, где что-то выходит из строя. Для этого вам нужно понять группировку в командах bash с использованием фигурных скобок.
Вместо a && b вы захотите написать:
a || { echo "a failed" && false; } && b || echo "b failed"
Существует еще один соединитель, с которым вы, возможно, не сталкивались: || - это то же самое, что и &&, за исключением того, что он выполняет вторую команду только в том случае, если первая завершилась с ненулевым (неудачным) статусом.
Никто не ответил на вопрос 4… Я подозреваю, что поведение && и || было вдохновлено языком программирования C. В случае (x && y), если x вычисляется как false, все выражение должно быть false, чтобы компилятор мог оптимизировать вычисление y, если это было дорого. Современные стандарты C и C++ на самом деле * требуют * такой оптимизации, поэтому программы могут с уверенностью предположить, что y не будет вычисляться, если x равно false. Например, (ptr && ptr->days > 31) не приведет к сбою, даже если ptr равен null. Также в C операторы заканчиваются на ; независимо от того, есть ли другой оператор в той же строке или нет.