Dlaczego nie mogę przekierować wyjścia nazwy ścieżki z jednego polecenia na „cd”?

27

Usiłuję uzyskać cdnazwę katalogu przekierowanego do niej z innego polecenia. Żadna z tych metod nie działa:

$ echo $HOME | cd
$ echo $HOME | xargs cd

Działa to:

$ cd $(echo $HOME)

Dlaczego pierwszy zestaw poleceń nie działa i czy istnieją inne, które również zawodzą w ten sposób?

Jhonathan
źródło
Czy inni odnoszą się do innych poleceń lub innych metod używania cd, które zawiodły w ten sposób?
Didi Kohen
@DavidKohen Odnoszę się do innych poleceń
Jhonathan
Niektóre godne uwagi przykłady to ulimit, umask, popd, pushd, set, export i read.
Didi Kohen

Odpowiedzi:

32

cdnie jest poleceniem zewnętrznym - jest to wbudowana funkcja powłoki. Działa w kontekście bieżącej powłoki, a nie, jak to robią polecenia zewnętrzne, w kontekście rozwidlenia / wykonania jako osobny proces.

Trzeci przykład działa, ponieważ powłoka rozwija zmienną i podstawianie poleceń przed wywołaniem cdwbudowanego, dzięki czemu cdotrzymuje wartość ${HOME}jako argument.

Systemy POSIX zrobić mają binarny cd- na moim komputerze FreeBSD, to co /usr/bin/cd, ale to nie to, co myślisz. Wywołanie pliku binarnego cdpowoduje, że powłoka rozwidla / wykonuje plik binarny, co faktycznie zmienia katalog roboczy na przekazywaną nazwę. Jednak gdy tylko to zrobi, binarne wyjście, a proces fork / exec'd znika, wracając do twojej powłoki, która wciąż znajduje się w katalogu, w którym była przed uruchomieniem.

D_Bye
źródło
10
Co sprawia, że ​​można się zastanawiać. Jaki jest sens cdpolecenia zewnętrznego ?
kojiro
23

cdnie odczytuje standardowego wejścia. Dlatego twój pierwszy przykład nie działa.

xargspotrzebuje nazwy polecenia, czyli niezależnego pliku wykonywalnego. cdmusi być wbudowanym poleceniem powłoki i nie miałoby żadnego efektu (oprócz sprawdzenia, czy można przejść do tego katalogu i potencjalnych skutków ubocznych, jakie może on mieć w przypadku katalogów automatycznych), gdyby był plikiem wykonywalnym. Dlatego twój drugi przykład nie działa.

mouviciel
źródło
4

Oprócz istniejącej dobrej odpowiedzi, warto również wspomnieć, że potok przygotowuje nowy proces, który ma swój osobny katalog roboczy. Dlatego próba zrobienia tego nie zadziała:

echo test | cd /

Dlatego nie będziesz w folderze / po powrocie powłoki z tego polecenia.

Mark Rejhon
źródło
Wszystkie polecenia w przebiegu rurociągu w różnych procesów, a więc w a | b, nawet jeśli ai bsą wbudowane, co najmniej jeden wtedy nie działa w procesie powłoki, ale nie ma gwarancji, który, który to jest. Na przykład w AT & T ksh, zshlub bash -O lastpipe, bprowadzony jest w obecnym procesie powłoki, dzięki czemu kod będzie można dostać się do / tam.
Stéphane Chazelas
4

Oprócz podanych już poprawnych odpowiedzi: Jeśli uruchomisz bash i chcesz dowiedzieć się, czym jest „polecenie”, takie jak cd , możesz użyć type

$ type cd
cd is a shell builtin

a dlaczego nie:

$ type time
time is a shell keyword

podczas gdy na przykład czas GNU jest zwykle zawarty w Twojej ulubionej dystrybucji:

$ which time
/usr/bin/time

Okej, dobrze, masz pomysł, a co to, u licha, jest?

$ type type
type is a shell builtin

Oto ręczny fragment kodu bash:

       type [-aftpP] name [name ...]
          With no options, indicate how each name would be interpreted  if  used  as  a
          command name.  If the -t option is used, type prints a string which is one of
          alias, keyword, function, builtin,  or  file  if  name  is  an  alias,  shell
          reserved word, function, builtin, or disk file, respectively.  If the name is
          not found, then nothing is printed, and an exit status of false is  returned.
          If  the -p option is used, type either returns the name of the disk file that
          would be executed if name were specified as a command  name,  or  nothing  if
          ‘‘type  -t  name’’ would not return file.  The -P option forces a PATH search
          for each name, even if ‘‘type -t name’’ would not return file.  If a  command
          is  hashed,  -p  and -P print the hashed value, not necessarily the file that
          appears first in PATH.  If the -a option is used,  type  prints  all  of  the
          places  that  contain  an  executable  named name.  This includes aliases and
          functions, if and only if the -p option is  not  also  used.   The  table  of
          hashed  commands  is  not  consulted when using -a.  The -f option suppresses
          shell function lookup, as with the command builtin.  type returns true if any
          of the arguments are found, false if none are found.
3molo
źródło
0

Jak powiedzieli inni, to nie zadziała, ponieważ cdjest to polecenie wbudowane w powłokę, a nie program zewnętrzny, więc nie ma żadnego standardowego wejścia, do którego można by coś potokować.

Ale nawet gdyby zadziałało, nie zrobiłoby tego, co chcesz: potok spawnuje nowy proces i przekierowuje standardowe wyjście pierwszego polecenia na standardowe wejście drugiego, dlatego tylko nowy proces zmieniłby jego bieżące działanie informator; nie mogło to w żaden sposób wpłynąć na pierwszy proces.

Massimo
źródło
2
Twój drugi akapit ma rację. Ale przejdź do pierwszego akapitu: dlaczego zakładasz, że wbudowane powłoki nie mają standardowego wejścia? readjest zwykle (zawsze?) wbudowany w powłokę. To prawda, że cdignoruje standardowe wejście, ale nie wynika to z jego wbudowania.
dubiousjim
-2

Inną opcją są backticks, które umieszczają stdout jednego polecenia jako argument wiersza poleceń drugiego polecenia i są bardziej przenośne niż $(...). Na przykład:

cd `echo $HOME`

lub bardziej ogólnie;

cd `anycommand -and whatever args`

Zauważ, że użycie backicksa zależy od powłoki do wykonania polecenia i podstawienia wyjścia w linii poleceń. Większość pocisków obsługuje to.

Seth Noble
źródło
3
OP stwierdził już w swoim pytaniu, że $(...)działa. Nie wydaje mi się, że dobrym pomysłem jest polecanie odwrotnych stron, ponieważ mają one znacznie bardziej skomplikowane reguły cytowania i generalnie są bardziej podatne na błędy. (Patrz §3.5.4 „Zastępowanie poleceń” w Podręczniku użytkownika Bash .)
ruakh,
$ () jest fajny tam, gdzie jest obsługiwany, ale backsticks są szerzej obsługiwane w różnych powłokach i systemach. Ale powinienem to sformułować jako „inną opcję”.
Seth Noble,
Różne muszle, tak; ale różne „systemy”? Czy naprawdę są jakieś powłoki, które będą obsługiwane $(...)w jednym systemie, ale nie w innym?
ruakh
4
-1, w ogóle nie odpowiada na pytanie.
Bernhard
3
@ruakh & Seth: Obsługa wszystkich powłok POSIX $(…). Systemy bez powłoki POSIX (tj. Z oryginalną powłoką Bourne'a) byłyby bardzo stare. Nawet systemy, w których /bin/shznajduje się powłoka Bourne'a i potrzebujesz innej ścieżki, /usr/xpg4/bin/shaby uzyskać powłokę POSIX, są obecnie rzadkością. Polecanie backtick'om każdemu, kto nie administruje starożytnym boxem unixowym, czyni z nich krzywdę.
Gilles „SO- przestań być zły”