В p=$(cd ~ && pwd)
Подстановка команды, $()
, запускается в подпрограмме
cd ~
изменяет каталог на ~
(ваш дом), если cd
успешно (&&
), то pwd
выводит имя каталога на STDOUT, следовательно, строка, сохраненная на p
, будет вашим домашним каталогом e. g. /home/foobar
В p=$(cd ~ | pwd)
:
Опять $()
порождает под-оболочку
Команды по обе стороны от |
выполняются в соответствующих под-оболочках (и обе запускаются одновременно)
поэтому cd ~
выполняется в под-оболочке, а pwd
в отдельной подоболочке
поэтому вы получите только STDOUT от pwd
, т.е. от того места, где вы запустили команду. т.е. из того места, откуда вы запускаете команду, это может быть любой каталог, как вы можете себе представить, следовательно, p
будет содержать имя каталога, из которого вызывается команда, а не ваш домашний каталог
Я не уверен, имели ли вы в виду '|' или '||' во втором случае.
'|' в командной оболочке передает вывод одной команды на вход другой - обычным примером является что-то вроде:
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
Основная проблема заключается в том, как операторы &&
и |
соединяют две команды.
&&
соединяет команды через код выхода.
|
соединяет две команды через файловые дескрипторы (stdin, stdout).
Давайте сначала упростим. Мы можем удалить назначение и написать:
echo $(cd ~ && pwd)
echo $(cd ~ | pwd)
Мы даже можем удалить суб-оболочку выполнения команд, чтобы проанализировать это:
$ cd ~ && pwd
$ cd ~ | pwd
Если мы изменим приглашение, чтобы показать каталог, в котором выполняются команды, что-то вроде PS1 = '\ w \ $'
, мы увидим это:
/tmp/user$ cd ~ && pwd
/home/user
~$
cd ~
изменила «текущий каталог» на домашний адрес фактического пользователя, выполняющего команду. ( / home / user
). 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)"
Просто напечатает каталог, в котором была выполнена команда.