Почему я не могу перенаправить вывод имени пути из одной команды в «cd»?


27

Я пытаюсь cdпринять имя каталога, перенаправленное на него от другой команды. Ни один из этих методов не работает:

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

Это работает:

$ cd $(echo $HOME)

Почему первый набор команд не работает, и есть другие, которые также терпят неудачу таким образом?


Под другими вы обращаетесь к другим командам или другим методам использования CD, которые терпят неудачу таким образом?
Диди Кохен

@DavidKohen Я имею в виду другие команды
Джонатан

Некоторые известные примеры: ulimit, umask, popd, pushd, set, export и read.
Диди Кохен

Ответы:


32

cdэто не внешняя команда - это встроенная функция оболочки. Он запускается в контексте текущей оболочки, а не, как внешние команды, в контексте fork / exec'd как отдельный процесс.

Ваш третий пример работает, потому что оболочка раскрывает переменную и подстановку команды перед вызовом cdвстроенного, так что cdполучает значение в ${HOME}качестве аргумента.

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


10
Что заставляет задуматься: в чем смысл внешней cdкоманды?
Кодзиро

23

cdне читает стандартный ввод. Вот почему ваш первый пример не работает.

xargsнеобходимо имя команды, то есть имя независимого исполняемого файла. cdдолжна быть встроенной командой оболочки и не иметь никакого эффекта (кроме проверки того, что вы можете перейти в этот каталог и возможные побочные эффекты, которые он может иметь, например, для автоматически монтируемых каталогов), если бы это был исполняемый файл. Вот почему ваш второй пример не работает.


4

В дополнение к существующему хорошему ответу также стоит упомянуть, что канал разветвляет новый процесс, который имеет свой отдельный рабочий каталог. Поэтому попытка сделать это не сработает:

echo test | cd /

Таким образом, вы не будете в папке / после того, как оболочка вернется из этой команды.


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

4

В дополнение к правильным ответам, которые уже даны: если вы запускаете bash и хотите узнать, что такое «команда», такая как cd, вы можете использовать type

$ 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

Вот фрагмент руководства 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.

0

Как уже говорили другие, это не сработает, потому что cdэто встроенная команда оболочки, а не внешняя программа, поэтому у нее нет стандартного ввода, в который можно что-либо передать.

Но, даже если бы это работало, это не сделало бы то, что вы хотите: канал запускает новый процесс и перенаправляет стандартный вывод первой команды на стандартный ввод второй, таким образом, только новый процесс изменит свою текущую работу каталог; это никак не могло повлиять на первый процесс.


2
Ваш второй абзац правильный. Но вернемся к первому абзацу: почему вы предполагаете, что встроенные функции оболочки не имеют стандартного ввода? readобычно (всегда?) встроенная оболочка. Это правда, что cdигнорирует стандартный ввод, но это не потому, что он встроен.
dubiousjim

-2

Другим вариантом являются обратные пометки, которые помещают стандартный вывод одной команды в качестве аргумента командной строки второй команды и являются более переносимыми, чем $(...). Например:

cd `echo $HOME`

или в более общем смысле;

cd `anycommand -and whatever args`

Обратите внимание, что использование обратных галочек зависит от оболочки для выполнения команды и замены вывода в командной строке. Большинство снарядов поддерживают это.


3
ОП уже заявил в своем вопросе, что это $(...)работает. Я не думаю, что это хороший совет, чтобы рекомендовать кавычки вместо этого, так как они имеют гораздо более запутанные правила цитирования и, как правило, более подвержены ошибкам. (См. §3.5.4 «Замена команд» в Справочном руководстве Bash .)
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.