@heemayl Спасибо. Можете ли вы извлечь различия по моему делу? Благодарю.
Нам G VU
1
Подсказка: команды по обе стороны |запускаются в подоболочках.
Heemayl
Ответы:
21
В p=$(cd ~ && pwd):
Подстановка команды $(), выполняется в подоболочке
cd ~меняет каталог на ~(ваш домашний), если cdуспешно ( &&) затем pwdпечатает имя каталога на STDOUT, следовательно, сохраненная строка pбудет вашим домашним каталогом, например/home/foobar
В p=$(cd ~ | pwd):
Снова $()порождает подоболочку
Команды с обеих сторон |запускаются в соответствующих подоболочках (и обе запускаются одновременно)
так cd ~делается в подоболочке, а pwdв отдельной оболочке
таким образом, вы получите только STDOUT, pwdто есть, откуда вы запускаете команду, это может быть любой каталог, который вы можете себе представить, следовательно, pбудет содержать имя каталога, из которого вызывается команда, а не ваш домашний каталог
Какова цель трубы между командами? cd ~не производит никакого вывода, и pwdне читает никакого ввода.
Бармар
Вторая команда по сути эквивалентна (cd ~);p=$(pwd)не так ли?
Бармар
@ Barmar Да, это то, что использовал OP, и я просто объясняю это для него.
Heemayl
7
Основная проблема заключается в том, как операторы &&и |соединяют две команды.
&&Соединяет команды с помощью кода выхода. |Соединяет две команды с помощью дескрипторов файлов (стандартного устройства ввода, стандартный вывод).
Давайте сначала упростим. Мы можем удалить назначение и написать:
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».
Каталог был изменен, но внутри вложенной оболочки $(…)измененный каталог печатается /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)"
Просто распечатает каталог, в котором была выполнена команда.
Я не уверен, что вы имели в виду '|' или '||' во втором случае
'|' в оболочке направляет вывод одной команды на вход другой - общий вариант использования выглядит примерно так:
curl http://abcd.com/efgh | grep ijkl
например, выполнить команду и использовать другую команду для обработки вывода команды.
В приведенном вами примере это довольно бессмысленно, поскольку cd обычно не генерирует никаких выходных данных, а pwd не ожидает никаких вводных данных.
'&&' и '||' хотя партнерские команды. Они предназначены для использования так же, как логические операторы «и» и «или» в большинстве языков. Тем не менее, выполняемые оптимизации дают им определенное поведение, которое является парадигмой программирования оболочки.
Чтобы определить результат логической операции «и», вам нужно только оценить второе условие, если первое условие выполнено успешно - если первое условие не выполнено, общий результат всегда будет ложным.
Чтобы определить результат логической операции «или», вам нужно только оценить второе условие, если первое условие не выполнено - если первое условие выполнено успешно, общий результат всегда будет истинным.
Таким образом, в оболочке, если у вас есть, command1 && command2command2будет выполняться только тогда, когда command1завершил и вернул успешный код результата. Если у вас command1 || command2command2будет выполнено, когда command1завершает, если command1возвращает код ошибки.
Другая распространенная парадигма - command1это команда test - она генерирует одну строку оператора if / then - например:
[ "$VAR" = "" ] && VAR="Value if empty"
Это (длинный) способ присвоения значения переменной, если она в данный момент пуста.
Есть много примеров использования этого процесса в другом месте на Stack Exchange
|
запускаются в подоболочках.Ответы:
В
p=$(cd ~ && pwd)
:Подстановка команды
$()
, выполняется в подоболочкеcd ~
меняет каталог на~
(ваш домашний), еслиcd
успешно (&&
) затемpwd
печатает имя каталога на STDOUT, следовательно, сохраненная строкаp
будет вашим домашним каталогом, например/home/foobar
В
p=$(cd ~ | pwd)
:Снова
$()
порождает подоболочкуКоманды с обеих сторон
|
запускаются в соответствующих подоболочках (и обе запускаются одновременно)так
cd ~
делается в подоболочке, аpwd
в отдельной оболочкетаким образом, вы получите только STDOUT,
pwd
то есть, откуда вы запускаете команду, это может быть любой каталог, который вы можете себе представить, следовательно,p
будет содержать имя каталога, из которого вызывается команда, а не ваш домашний каталогисточник
cd ~
не производит никакого вывода, иpwd
не читает никакого ввода.(cd ~);p=$(pwd)
не так ли?Основная проблема заключается в том, как операторы
&&
и|
соединяют две команды.&&
Соединяет команды с помощью кода выхода.|
Соединяет две команды с помощью дескрипторов файлов (стандартного устройства ввода, стандартный вывод).Давайте сначала упростим. Мы можем удалить назначение и написать:
Мы можем даже удалить под-оболочку выполнения команды, чтобы проанализировать это:
&&
Если мы изменим приглашение, чтобы показать каталог, в котором выполняются команды, что-то вроде этого
PS1='\w\$ '
, мы увидим это:cd ~
изменила «существующий каталог» на домашний каталог реального пользователя, который выполняет команду (/home/user
).pwd
на,~
показанное подсказкой~$
.Если по какой-либо причине изменение каталога не было выполнено (код выхода не равен 0) (каталог не существует, блок разрешений на чтение каталога) следующая команда не будет выполнена.
Пример:
Код выхода из 1
false
запрещает выполнение следующей команды.Таким образом, код выхода «команды 1» - это то, что влияет на «команду 2».
Теперь эффекты всей команды:
Каталог был изменен, но внутри вложенной оболочки
$(…)
измененный каталог печатается/home/user
, но сразу же удаляется при закрытии вложенной оболочки. Pwd возвращается в исходный каталог (/tmp/user
).|
Вот что происходит:
Мета-символ
|
(не истинный оператор) сигнализирует оболочке о создании так называемой «трубы», (в bash) каждая команда на каждой стороне канала (|
) задается внутри каждой собственной субоболочки, сначала с правой стороны команда, то левый. Дескриптор входного файла (/dev/stdin
) правой команды подключается к выходному дескриптору (/dev/stdout
), а затем обе команды запускаются и оставляются для взаимодействия. У левой команды (cd -
) нет выходных данных, а также у правой команды (pwd
) нет входных данных. Таким образом, каждый из них работает независимо внутри каждой собственной суб-оболочки.cd ~
Изменяет PWD одной оболочки.pwd
Печатает (полностью независимую) PWD другого суб-оболочки.Изменения в каждой оболочке отбрасываются, когда заканчивается канал, внешняя вложенная оболочка не изменила pwd.
Вот почему две команды связаны только «файловыми дескрипторами».
В этом случае ничего не отправляется и ничего не читается.
Вся команда:
Просто распечатает каталог, в котором была выполнена команда.
источник
Я не уверен, что вы имели в виду '|' или '||' во втором случае
'|' в оболочке направляет вывод одной команды на вход другой - общий вариант использования выглядит примерно так:
curl http://abcd.com/efgh | grep ijkl
например, выполнить команду и использовать другую команду для обработки вывода команды.В приведенном вами примере это довольно бессмысленно, поскольку cd обычно не генерирует никаких выходных данных, а pwd не ожидает никаких вводных данных.
'&&' и '||' хотя партнерские команды. Они предназначены для использования так же, как логические операторы «и» и «или» в большинстве языков. Тем не менее, выполняемые оптимизации дают им определенное поведение, которое является парадигмой программирования оболочки.
Чтобы определить результат логической операции «и», вам нужно только оценить второе условие, если первое условие выполнено успешно - если первое условие не выполнено, общий результат всегда будет ложным.
Чтобы определить результат логической операции «или», вам нужно только оценить второе условие, если первое условие не выполнено - если первое условие выполнено успешно, общий результат всегда будет истинным.
Таким образом, в оболочке, если у вас есть,
command1 && command2
command2
будет выполняться только тогда, когдаcommand1
завершил и вернул успешный код результата. Если у васcommand1 || command2
command2
будет выполнено, когдаcommand1
завершает, еслиcommand1
возвращает код ошибки.Другая распространенная парадигма -
command1
это команда test - она генерирует одну строку оператора if / then - например:[ "$VAR" = "" ] && VAR="Value if empty"
Это (длинный) способ присвоения значения переменной, если она в данный момент пуста.
Есть много примеров использования этого процесса в другом месте на Stack Exchange
источник