В чем разница между && и | в сценарии bash?

ПУТЬ = $ ПУТЬ: /node/v4.2.6/bin/ ./start.sh

12
14.11.2016, 17:39
3 ответа

В p=$(cd ~ && pwd)

  • Подстановка команды, $(), запускается в подпрограмме

  • cd ~ изменяет каталог на ~ (ваш дом), если cd успешно (&&), то pwd выводит имя каталога на STDOUT, следовательно, строка, сохраненная на p, будет вашим домашним каталогом e. g. /home/foobar

В p=$(cd ~ | pwd):

  • Опять $() порождает под-оболочку

  • Команды по обе стороны от | выполняются в соответствующих под-оболочках (и обе запускаются одновременно)

  • поэтому cd ~ выполняется в под-оболочке, а pwd в отдельной подоболочке

  • поэтому вы получите только STDOUT от pwd, т.е. от того места, где вы запустили команду. т.е. из того места, откуда вы запускаете команду, это может быть любой каталог, как вы можете себе представить, следовательно, p будет содержать имя каталога, из которого вызывается команда, а не ваш домашний каталог

22
27.01.2020, 19:54

Я не уверен, имели ли вы в виду '|' или '||' во втором случае.

'|' в командной оболочке передает вывод одной команды на вход другой - обычным примером является что-то вроде: curl http://abcd.com/efgh | grep ijkl т.е. запустить команду и использовать другую команду для обработки вывода команды.

В приведенном вами примере это довольно бессмысленно, поскольку 'cd' обычно не генерирует никакого вывода, а 'pwd' не ожидает никакого ввода.

'&&' и '||' - это команды-партнеры. Они предназначены для использования так же, как логические операторы "and" и "or" в большинстве языков. Однако выполняемая оптимизация придает им специфическое поведение, которое является парадигмой программирования оболочки.

Чтобы определить результат логической операции "и", вам нужно оценить второе условие только в том случае, если первое условие выполнено - если первое условие не выполнено, общий результат всегда будет ложным.

Чтобы определить результат логической операции "или", достаточно оценить второе условие, если первое условие не выполняется - если первое условие выполняется, общий результат всегда будет истинным.

Так, в командной оболочке, если у вас есть command1 && command2 command2 будет выполнена только тогда, когда command1 завершилась и вернула код успешного результата. Если у вас есть command1 || command2 command2 будет выполнена, когда command1 завершится, если command1 вернет код неудачи.

Другая распространенная парадигма заключается в том, что command1 является тестовой командой - это генерирует однострочный оператор if/then - например:

["$VAR" = "" ] && VAR="Значение, если пусто"

Это (длинный) способ присвоения значения переменной, если в данный момент она пуста.

Есть много примеров использования этого процесса в других местах на Stack Exchange

6
27.01.2020, 19:54

Основная проблема заключается в том, как операторы && и | соединяют две команды.

&& соединяет команды через код выхода. | соединяет две команды через файловые дескрипторы (stdin, stdout).

Давайте сначала упростим. Мы можем удалить назначение и написать:

echo $(cd ~ && pwd)
echo $(cd ~ | pwd)

Мы даже можем удалить суб-оболочку выполнения команд, чтобы проанализировать это:

$ cd ~ && pwd
$ cd ~ | pwd

&&

Если мы изменим приглашение, чтобы показать каталог, в котором выполняются команды, что-то вроде PS1 = '\ w \ $' , мы увидим это:

/tmp/user$ cd ~ && pwd
/home/user
~$ 
  • Команда cd ~ изменила «текущий каталог» на домашний адрес фактического пользователя, выполняющего команду. ( / home / user ).
  • Поскольку результат команды был успешным (код выхода 0), выполняется следующая команда после &&
  • И «текущий рабочий каталог» печатается.
  • Работающая оболочка изменила свой pwd на ~ , как показано в приглашении ~ $ .

Если смена каталога по какой-либо причине была неудачной (код выхода не 0) (каталог не существует, права доступа блокируют чтение каталога), следующая команда не будет выполнена.

Пример:

/tmp/user$ false && pwd
/tmp/user$ _ 

Код выхода 1 из false предотвращает выполнение следующей команды.

Таким образом, код выхода «команды 1» влияет на «команду 2».

Теперь, эффекты всей команды:

/tmp/user$ echo $(cd ~ && pwd)
/home/user
/tmp/user$ _

Каталог был изменен, но внутри суб-оболочки $ (…) измененный каталог печатается / home / user , но немедленно отбрасывается как суб-оболочка закрывается. Pwd возвращается в исходный каталог ( / tmp / user ).

|

Вот что происходит:

/tmp/user$ cd ~ | pwd
/tmp/user
/tmp/user$ _

Метасимвол | (не настоящий оператор) сигнализирует оболочке создать так называемую «трубу» (в bash) каждый команды на каждой стороне канала ( | ) устанавливаются внутри каждой собственной суб-оболочки, сначала правая команда, затем левая. Дескриптор входного файла ( / dev / stdin ) правой команды подключается к выходному дескриптору ( / dev / stdout ), а затем обе команды запускаются и остаются для взаимодействия. Левая команда ( cd - ) не имеет вывода, а также правая команда ( pwd ) не принимает никаких входных данных. Таким образом, каждый из них работает независимо внутри каждой собственной суб-оболочки.

  • cd ~ изменяет pwd одной оболочки.
  • pwd печатает (полностью независимый) pwd другой суб-оболочки.

Изменения в каждой оболочке отменяются, когда труба заканчивается, внешняя вспомогательная оболочка не изменила pwd.

Поэтому две команды связаны только «файловыми дескрипторами».
В этом случае ничего не отправлено и ничего не прочитано.

Вся команда:

$ echo "$(cd ~ | pwd)"

Просто напечатает каталог, в котором была выполнена команда.

9
27.01.2020, 19:54

Теги

Похожие вопросы