Візьмемо два рядки нижче, які дають нам два різні результати.
p=$(cd ~ && pwd) ; echo $p
p=$(cd ~ | pwd) ; echo $p
Чим вони відрізняються?
|виконуються в підрозділах .
Візьмемо два рядки нижче, які дають нам два різні результати.
p=$(cd ~ && pwd) ; echo $p
p=$(cd ~ | pwd) ; echo $p
Чим вони відрізняються?
|виконуються в підрозділах .
Відповіді:
В p=$(cd ~ && pwd):
Підстановка команд $(), працює в нижній частині
cd ~змінить каталог на ~(ваш будинок), якщо cdуспішно ( &&), то pwdнадрукує ім'я каталогу в STDOUT, отже, рядок, збережений на, pбуде вашим домашнім каталогом, наприклад/home/foobar
В p=$(cd ~ | pwd):
Знову $()породжує передпластя
Команди з обох сторін |виконуються у відповідних підшах (і обидва починаються одночасно)
так cd ~це робиться як в підпакеті, так і pwdв окремій підпакеті
таким чином, ви отримаєте тільки STDOUT, pwdтобто звідки ви запускаєте команду, це може бути будь-який каталог, як ви можете собі уявити, отже, pбуде містити ім'я каталогу, звідки викликається команда, а не ваш домашній каталог
cd ~не дає жодного результату і pwdне читає жодного вводу.
(cd ~);p=$(pwd)чи не так?
Основне питання полягає в тому, як оператори &&і |з'єднають дві команди.
&&Поєднує команди з допомогою коду виходу. |З'єднує дві команди з допомогою дескрипторів файлів (стандартного пристрою введення, стандартний висновок).
Давайте спочатку спростимо. Ми можемо видалити завдання та написати:
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)"
Буде просто надрукувати каталог, де виконувалася команда.
Я не впевнений, чи ти мав на увазі "|" або '||' у вашому другому випадку.
'|' в оболонці передається вихід однієї команди на вхід іншої - загальний випадок використання є чимось на зразок:
curl http://abcd.com/efgh | grep ijkl
тобто виконайте команду та використовуйте іншу команду для обробки результатів команди.
У наведеному прикладі він є досить безглуздим, оскільки "cd", як правило, не генерує жодного результату, а "pwd" не очікує жодного введення.
'&&' та '||' є командами партнера. Вони розроблені так, щоб використовуватись так само, як і логічні оператори "та" і "або" на більшості мов. Однак оптимізації, які виконуються, дають їм специфічну поведінку, яка є парадигмою програмування оболонок.
Щоб визначити результат логічної операції "і", вам потрібно лише оцінити другу умову, якщо перша умова успішна - якщо перша умова не виконана, загальний результат завжди буде помилковим.
Щоб визначити результат логічної операції "чи", вам потрібно лише оцінити другу умову, якщо перша умова не виконана - якщо перша умова вдається, загальний результат завжди буде істинним.
Отже, в оболонці, якщо у вас є, command1 && command2 command2він буде виконаний лише після command1завершення та повернення успішного коду результату. Якщо у вас command1 || command2 command2буде виконано, коли command1завершено, якщо command1повертається код відмови.
Іншою поширеною парадигмою є command1тестова команда - це генерує єдиний рядок оператора if / then - наприклад:
[ "$VAR" = "" ] && VAR="Value if empty"
Це (довгомотовий) спосіб присвоєння значення змінній, якщо вона наразі порожня.
Існує багато прикладів використання цього процесу в інших місцях на Stack Exchange