@heemayl Thanks. Czy możesz wyodrębnić różnice w mojej sprawie? Dzięki.
Nam G VU
1
Wskazówka: polecenia po obu stronach |uruchamiania w podpowłokach.
heemayl
Odpowiedzi:
21
W p=$(cd ~ && pwd):
Podstawienie polecenia $(), działa w podpowłoce
cd ~zmienia katalog na ~(twój dom), jeśli się cdpowiedzie ( &&), następnie pwdwypisuje nazwę katalogu na STDOUT, stąd zapisany ciąg pbędzie katalogiem domowym np./home/foobar
W p=$(cd ~ | pwd):
Ponownie $()pojawia się podpowłoka
Komendy po obu stronach |uruchamiania w odpowiednich podpowłokach (i obie rozpoczynają się w tym samym czasie)
tak cd ~odbywa się w podpowłoce oraz pwdw oddzielnym podpowłoce
więc dostaniesz tylko STDOUT, pwdtj. z miejsca, w którym uruchomisz polecenie, może to być dowolny katalog, jak możesz sobie wyobrazić, a zatem pbędzie on zawierał nazwę katalogu, z którego polecenie jest wywoływane, a nie katalog domowy
Jaki jest cel potoku między poleceniami? cd ~nie generuje żadnych danych wyjściowych i pwdnie odczytuje żadnych danych wejściowych.
Barmar,
Drugie polecenie jest zasadniczo równoważne, (cd ~);p=$(pwd)prawda?
Barmar,
@Barmar Tak, właśnie tego użył OP i właśnie mu to tłumaczę.
heemayl
7
Podstawowym problemem jest sposób, w jaki operatorzy &&i |łączą oba polecenia.
&&Łączy polecenia za pośrednictwem kodu wyjścia. |Łączy dwa polecenia za pomocą deskryptorów (stdin, stdout).
Uprośćmy najpierw. Możemy usunąć zadanie i napisać:
echo $(cd ~&& pwd)
echo $(cd ~| pwd)
Możemy nawet usunąć podpowłokę wykonania polecenia, aby to przeanalizować:
$ cd ~&& pwd
$ cd ~| pwd
I &
Jeśli zmienimy monit, aby pokazać katalog, w którym wykonywane są polecenia, coś w PS1='\w\$ 'tym stylu:
/tmp/user$ cd ~&& pwd
/home/user
~$
Polecenie cd ~zmieniło „obecny katalog” na domową wersję użytkownika, który wykonuje polecenie ( /home/user).
Ponieważ wynik polecenia powiódł się (kod wyjścia 0), następne polecenie po wykonaniu && zostanie wykonane
I drukowany jest „obecny katalog roboczy”.
Działająca powłoka zmieniła swoją pwdna, ~jak pokazuje monit ~$.
Jeśli z jakiegoś powodu zmiana katalogu nie powiodła się (kod wyjścia nie wynosi 0) (katalog nie istnieje, blok uprawnień odczytu katalogu) następna komenda nie zostanie wykonana.
Przykład:
/tmp/user$ false && pwd
/tmp/user$ _
Kod wyjścia 1 z falseuniemożliwia wykonanie następnego polecenia.
Zatem kod wyjścia „polecenia 1” wpływa na „polecenie 2”.
Katalog został zmieniony, ale wewnątrz podpowłoki $(…)zmieniony katalog jest drukowany /home/user, ale jest natychmiast odrzucany po zamknięciu podpowłoki. Pwd wraca do katalogu początkowego ( /tmp/user).
|
Oto co się dzieje:
/tmp/user$ cd ~| pwd
/tmp/user
/tmp/user$ _
Metaznak |(nie prawdziwy operator) sygnalizuje powłoce utworzenie „potoku”, (w skrócie) każde polecenie po każdej stronie potoku ( |) jest ustawione wewnątrz każdej własnej podpowłoki, najpierw po prawej stronie polecenie, a następnie lewy. Deskryptor pliku wejściowego ( /dev/stdin) prawego polecenia jest połączony z deskryptorem wyjściowym ( /dev/stdout), a następnie oba polecenia są uruchamiane i pozostawione do interakcji. Lewe polecenie ( cd -) nie ma danych wyjściowych, a także prawe polecenie ( pwd) nie przyjmuje danych wejściowych. Tak więc każdy działa niezależnie w każdej własnej podpowłoce.
cd ~Zmienia pwd jednej powłoce.
pwdDrukuje (PWD) całkowicie niezależne od innych pod-obudowy.
Zmiany w każdej powłoce są odrzucane, gdy rura się kończy, zewnętrzna podpowłoka nie zmieniła PWD.
Dlatego te dwa polecenia są połączone tylko przez „deskryptory plików”.
W tym przypadku nic nie jest wysyłane i nic nie jest czytane.
Całe polecenie:
$ echo "$(cd ~ | pwd)"
Po prostu wydrukuje katalog, w którym polecenie zostało wykonane.
Nie jestem pewien, czy miałeś na myśli „|” lub „||” w twoim drugim przypadku.
„|” w powłoce potokuje wyjście jednego polecenia na wejście innego - częstym przypadkiem użycia jest coś takiego:
curl http://abcd.com/efgh | grep ijkl
np. uruchom polecenie i użyj innego polecenia, aby przetworzyć wynik polecenia.
W podanym przykładzie jest to dość nonsensowne, ponieważ „cd” zwykle nie generuje żadnych danych wyjściowych, a „pwd” nie oczekuje żadnych danych wejściowych.
„&&” i „||” są jednak poleceniami partnerów. Są zaprojektowane tak, aby można było z nich korzystać w taki sam sposób, jak operatory logiczne „i” i „lub” w większości języków. Jednak przeprowadzane optymalizacje nadają im określone zachowanie, które jest paradygmatem programowania powłoki.
Aby określić wynik operacji logicznej „i”, należy ocenić drugi warunek tylko wtedy, gdy pierwszy warunek się powiedzie - jeśli pierwszy warunek się nie powiedzie, ogólny wynik zawsze będzie fałszywy.
Aby określić wynik operacji logicznej „lub”, musisz ocenić drugi warunek tylko wtedy, gdy pierwszy warunek się nie powiedzie - jeśli pierwszy warunek się powiedzie, ogólny wynik zawsze będzie prawdziwy.
Tak więc w powłoce, jeśli ją wykonasz, command1 && command2command2zostanie wykonany dopiero po command1zakończeniu i zwróceniu pomyślnego kodu wynikowego. Jeśli masz, command1 || command2command2zostanie wykonany po command1zakończeniu, jeśli command1zwróci kod błędu.
Innym powszechnym paradygmatem jest command1komenda testowa - generuje ona pojedynczą instrukcję if / then - na przykład:
[ "$VAR" = "" ] && VAR="Value if empty"
Jest (długo rozwiniętym) sposobem przypisywania wartości zmiennej, jeśli jest ona obecnie pusta.
Istnieje wiele przykładów zastosowania tego procesu w innym miejscu na Stack Exchange
|
uruchamiania w podpowłokach.Odpowiedzi:
W
p=$(cd ~ && pwd)
:Podstawienie polecenia
$()
, działa w podpowłocecd ~
zmienia katalog na~
(twój dom), jeśli sięcd
powiedzie (&&
), następniepwd
wypisuje nazwę katalogu na STDOUT, stąd zapisany ciągp
będzie katalogiem domowym np./home/foobar
W
p=$(cd ~ | pwd)
:Ponownie
$()
pojawia się podpowłokaKomendy po obu stronach
|
uruchamiania w odpowiednich podpowłokach (i obie rozpoczynają się w tym samym czasie)tak
cd ~
odbywa się w podpowłoce orazpwd
w oddzielnym podpowłocewięc dostaniesz tylko STDOUT,
pwd
tj. z miejsca, w którym uruchomisz polecenie, może to być dowolny katalog, jak możesz sobie wyobrazić, a zatemp
będzie on zawierał nazwę katalogu, z którego polecenie jest wywoływane, a nie katalog domowyźródło
cd ~
nie generuje żadnych danych wyjściowych ipwd
nie odczytuje żadnych danych wejściowych.(cd ~);p=$(pwd)
prawda?Podstawowym problemem jest sposób, w jaki operatorzy
&&
i|
łączą oba polecenia.&&
Łączy polecenia za pośrednictwem kodu wyjścia.|
Łączy dwa polecenia za pomocą deskryptorów (stdin, stdout).Uprośćmy najpierw. Możemy usunąć zadanie i napisać:
Możemy nawet usunąć podpowłokę wykonania polecenia, aby to przeanalizować:
I &
Jeśli zmienimy monit, aby pokazać katalog, w którym wykonywane są polecenia, coś w
PS1='\w\$ '
tym stylu:cd ~
zmieniło „obecny katalog” na domową wersję użytkownika, który wykonuje polecenie (/home/user
).pwd
na,~
jak pokazuje monit~$
.Jeśli z jakiegoś powodu zmiana katalogu nie powiodła się (kod wyjścia nie wynosi 0) (katalog nie istnieje, blok uprawnień odczytu katalogu) następna komenda nie zostanie wykonana.
Przykład:
Kod wyjścia 1 z
false
uniemożliwia wykonanie następnego polecenia.Zatem kod wyjścia „polecenia 1” wpływa na „polecenie 2”.
Teraz efekty całego polecenia:
Katalog został zmieniony, ale wewnątrz podpowłoki
$(…)
zmieniony katalog jest drukowany/home/user
, ale jest natychmiast odrzucany po zamknięciu podpowłoki. Pwd wraca do katalogu początkowego (/tmp/user
).|
Oto co się dzieje:
Metaznak
|
(nie prawdziwy operator) sygnalizuje powłoce utworzenie „potoku”, (w skrócie) każde polecenie po każdej stronie potoku (|
) jest ustawione wewnątrz każdej własnej podpowłoki, najpierw po prawej stronie polecenie, a następnie lewy. Deskryptor pliku wejściowego (/dev/stdin
) prawego polecenia jest połączony z deskryptorem wyjściowym (/dev/stdout
), a następnie oba polecenia są uruchamiane i pozostawione do interakcji. Lewe polecenie (cd -
) nie ma danych wyjściowych, a także prawe polecenie (pwd
) nie przyjmuje danych wejściowych. Tak więc każdy działa niezależnie w każdej własnej podpowłoce.cd ~
Zmienia pwd jednej powłoce.pwd
Drukuje (PWD) całkowicie niezależne od innych pod-obudowy.Zmiany w każdej powłoce są odrzucane, gdy rura się kończy, zewnętrzna podpowłoka nie zmieniła PWD.
Dlatego te dwa polecenia są połączone tylko przez „deskryptory plików”.
W tym przypadku nic nie jest wysyłane i nic nie jest czytane.
Całe polecenie:
Po prostu wydrukuje katalog, w którym polecenie zostało wykonane.
źródło
Nie jestem pewien, czy miałeś na myśli „|” lub „||” w twoim drugim przypadku.
„|” w powłoce potokuje wyjście jednego polecenia na wejście innego - częstym przypadkiem użycia jest coś takiego:
curl http://abcd.com/efgh | grep ijkl
np. uruchom polecenie i użyj innego polecenia, aby przetworzyć wynik polecenia.W podanym przykładzie jest to dość nonsensowne, ponieważ „cd” zwykle nie generuje żadnych danych wyjściowych, a „pwd” nie oczekuje żadnych danych wejściowych.
„&&” i „||” są jednak poleceniami partnerów. Są zaprojektowane tak, aby można było z nich korzystać w taki sam sposób, jak operatory logiczne „i” i „lub” w większości języków. Jednak przeprowadzane optymalizacje nadają im określone zachowanie, które jest paradygmatem programowania powłoki.
Aby określić wynik operacji logicznej „i”, należy ocenić drugi warunek tylko wtedy, gdy pierwszy warunek się powiedzie - jeśli pierwszy warunek się nie powiedzie, ogólny wynik zawsze będzie fałszywy.
Aby określić wynik operacji logicznej „lub”, musisz ocenić drugi warunek tylko wtedy, gdy pierwszy warunek się nie powiedzie - jeśli pierwszy warunek się powiedzie, ogólny wynik zawsze będzie prawdziwy.
Tak więc w powłoce, jeśli ją wykonasz,
command1 && command2
command2
zostanie wykonany dopiero pocommand1
zakończeniu i zwróceniu pomyślnego kodu wynikowego. Jeśli masz,command1 || command2
command2
zostanie wykonany pocommand1
zakończeniu, jeślicommand1
zwróci kod błędu.Innym powszechnym paradygmatem jest
command1
komenda testowa - generuje ona pojedynczą instrukcję if / then - na przykład:[ "$VAR" = "" ] && VAR="Value if empty"
Jest (długo rozwiniętym) sposobem przypisywania wartości zmiennej, jeśli jest ona obecnie pusta.
Istnieje wiele przykładów zastosowania tego procesu w innym miejscu na Stack Exchange
źródło