Чому я не можу перенаправити вихідну назву шляху з однієї команди на "cd"?


27

Я намагаюся змусити cdприйняти ім’я каталогу, перенаправлене на нього з іншої команди. Жоден із цих методів не працює:

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

Це працює:

$ cd $(echo $HOME)

Чому перший набір команд не працює, а є й інші, які також не справляються таким чином?


Іншими ви звертаєтесь до інших команд чи інших методів використання CD, які виходять з ладу таким чином?
Діді Кохен

@DavidKohen Я маю на увазі інші команди
Джонатан

Деякі помітні приклади - ulimit, umask, popd, pushd, встановити, експортувати та читати.
Діді Коен

Відповіді:


32

cdне є зовнішньою командою - це функція, побудована в оболонці. Він працює в контексті поточної оболонки, а не, як це роблять зовнішні команди, в контексті fork / exec'd як окремий процес.

Третій приклад працює, оскільки оболонка розширює змінну та підстановку команд перед викликом cdвбудованого, таким чином, що cdотримує значення ${HOME}як її аргумент.

Системи POSIX роблять мають бінарний cd- на моїй машині FreeBSD, це на /usr/bin/cd, але він не робить те , що ви думаєте. Виклик бінарного файлу cdпризводить до того, що оболонка розкручує / виконує бінарний файл, що дійсно змінює свій робочий каталог на ім'я, яке ви передаєте. Однак, як тільки це зробить, двійковий файл виходить, і процес forked / exec'd зникає, повертаючи вас до своєї оболонки, яка все ще знаходиться в каталозі, в якому вона знаходилась до початку роботи.


10
Що змушує задатися питанням У чому полягає зміст зовнішньої cdкоманди?
kojiro

23

cdне читає стандартний вхід. Ось чому ваш перший приклад не працює.

xargsпотребує імені команди, тобто імені незалежного виконуваного файлу. cdповинна бути вбудованою командою оболонки і не матиме жодного ефекту (крім перевірки того, що ви можете змінити цей каталог та можливі побічні ефекти, які він може мати, як для автоматичних директорій), якби він був виконуваним. Ось чому ваш другий приклад не працює.


4

Окрім існуючої гарної відповіді, також варто згадати, що труба розгалужує новий процес, який має свій окремий робочий каталог. Тому, намагаючись це зробити, не вийде:

echo test | cd /

Таким чином, ви не опинитесь в папці / після повернення оболонки з цієї команди.


Усі команди в трубопроводі виконуються в різних процесах, тому a | b, навіть якщо aі bвбудовані, принаймні одна, тоді не виконується в оболонковому процесі, але немає гарантії, який це. Наприклад, AT&T ksh, zshабо bash -O lastpipe, bвиконується в поточному процесі оболонки, тож ваш код переведе вас туди / туди.
Стефан Шазелас

4

На додаток до правильних відповідей, які вже були надані: Якщо ви запускаєте bash і хочете дізнатися, що таке "команда", як cd, ви можете використовувати тип

$ type cd
cd is a shell builtin

або чому ні:

$ type time
time is a shell keyword

хоча, наприклад, час gnu зазвичай включено до вашого улюбленого розповсюдження:

$ which time
/usr/bin/time

Окей гаразд, ви зрозуміли, що ж тут за хек?

$ type type
type is a shell builtin

Ось базовий фрагмент вручну:

       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.

0

Як говорили інші, вона не працюватиме, оскільки cdце команда, вбудована в оболонку, а не зовнішня програма, тому в неї немає стандартного вводу, в який ви можете вставити що-небудь.

Але, навіть якби це працювало, воно не робило б того, що ви хочете: труба породить новий процес і перенаправляє стандартний вихід першої команди на стандартний вхід другої, таким чином, лише новий процес змінить поточну роботу каталог; це ніяк не могло вплинути на перший процес.


2
Ваш другий абзац правильний. Але знову перший абзац: чому ви вважаєте, що оболонки в корпусі не мають stdin? readзазвичай є (завжди?) вбудованою оболонкою. Це правда, що cdігнорує stdin, але це не через те, що він є вбудованим.
сумнівним

-2

Іншим варіантом є зворотні посилання, які розміщують stdout однієї команди як аргумент командного рядка другої команди та є більш портативними, ніж $(...). Наприклад:

cd `echo $HOME`

або в більш загальному вигляді;

cd `anycommand -and whatever args`

Зауважте, що використання зворотних посилань залежить від оболонки для виконання команди та підстановки виводу в командному рядку. Більшість снарядів це підтримує.


3
В своєму питанні ОП вже зазначило, що це $(...)працює. Я не вважаю, що рекомендувати замість цього зворотних посилань, оскільки вони мають набагато більш суперечливі правила цитування і, як правило, більш схильні до помилок. (Див. §5.5.4 "Заміна команди" в Довідковому посібнику Баша .)
ruakh

$ () приємно там, де він підтримується, але бекстіки більш широко підтримуються в різних оболонках та системах. Але я повинен перефразувати це як "інший варіант".
Сет Благородний

Різні снаряди, так; але різні "системи"? Чи дійсно є оболонки, які підтримуватимуть $(...)одну систему, а не іншу ??
ruakh

4
-1, це зовсім не відповідає на питання.
Бернхард

3
@ruakh & Seth: Усі оболонки POSIX підтримують $(…). Системи без POSIX оболонки (тобто з справжньою оболонкою Bourne) були б надзвичайно старими. Навіть системи, де /bin/shє оболонка Bourne, і вам потрібен інший шлях, такий як /usr/xpg4/bin/shотримати оболонку POSIX, є рідкісними на сьогоднішній день. Рекомендуючи бекстик для всіх, хто не керує стародавним Unix boxen професійно, робить їх недобрими послугами.
Жил "ТАК - перестань бути злим"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.