为什么不能将一个命令的路径名输出重定向到“ cd”?


27

我试图cd接受从另一个命令重定向到它的目录名称。这些方法都不起作用:

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

这确实有效:

$ cd $(echo $HOME)

为什么第一组命令不起作用,还有其他命令也会失败吗?


在其他人看来,您是指其他以这种方式失败的命令或方法来使用cd吗?
Didi Kohen

@DavidKohen我提到其他命令
Jhonathan

一些著名的例子是ulimit,umask,popd,pushed,set,export和read。
Didi Kohen

Answers:


32

cd不是外部命令-它是Shell内置函数。它在当前shell的上下文中运行,而不像外部命令那样在fork / exec的上下文中作为单独的进程运行。

您的第三个示例可行,因为shell在调用cd内置函数之前先扩展变量和命令替换,以便cd接收值${HOME}作为其参数。

POSIX系统确实有一个二进制文件cd-在我的FreeBSD机器上,它位于/usr/bin/cd,但没有按照您的想法运行。调用二进制文件cd会导致外壳派生/执行该二进制文件,这确实会将其工作目录更改为您传递的名称。但是,一旦这样做,二进制文件就会退出,并且分叉/执行的进程会消失,将您带回到您的shell,该shell仍位于开始之前的目录中。



23

cd不读取标准输入。这就是为什么您的第一个示例不起作用的原因。

xargs需要命令名称,即独立可执行文件的名称。cd如果它是可执行文件,则它必须是shell内置命令,并且没有任何作用(除了验证您可以更改到该目录以及它对自动挂载目录的潜在副作用外)。这就是为什么您的第二个示例不起作用的原因。


4

除了现有的良好答案外,还值得一提的是,管道派生了一个新进程,该进程具有自己的单独工作目录。因此,尝试执行此操作将无效:

echo test | cd /

因此,shell从此命令返回后,您将不在/文件夹中。


管道中的所有命令都在不同的进程中运行,因此在中a | b,即使ab都是内置的,也至少有一个命令不会在shell进程中运行,但是不能保证它是哪一个。例如,在AT&T kshzsh或中bash -O lastpipeb是在当前Shell进程中运行的,因此您的代码会将您带到/那里。
斯特凡Chazelas

4

除了已经给出的正确答案之外:如果您运行bash并想找出cd之类的“命令”,则可以使用type

$ type cd
cd is a shell builtin

或为什么不:

$ type time
time is a shell keyword

而例如,通常您喜欢的发行版中已经包含了gnu time:

$ 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是行不通的,因为它是Shell内置命令,而不是外部程序,因此它没有任何标准输入,您可以将任何内容输入其中。

但是,即使它起作用了,也无法满足您的期望:管道产生了一个新进程,并将第一个命令的标准输出重定向到第二个命令的标准输入,因此只有新进程才能更改其当前的工作状态目录; 这不会以任何方式影响第一个过程。


2
您的第二段是正确的。但是,重新开始第一段:为什么您假设shell内置程序没有标准输入?read通常是(总是?)内置的shell。确实可以cd忽略stdin,但这不是由于它是内置函数。
dubiousjim

-2

另一个选择是反引号,它会将一个命令的标准输出作为第二个命令的命令行参数,并且比更具可移植性$(...)。例如:

cd `echo $HOME`

或更一般地;

cd `anycommand -and whatever args`

请注意,反引号的使用取决于用于执行命令并替换命令行上的输出的外壳。大多数shell支持它。


3
OP在他/她的问题中已经说过$(...)可行。我认为推荐反引号不是一个好建议,因为反引号的报价规则复杂得多,而且通常更容易出错。(请参阅Bash参考手册中的第3.5.4节“命令替换”。)
ruakh 2012年

$()在受支持的地方很好,但是反引号在不同的shell和系统中得到更广泛的支持。但是,我应该将其改写为“另一种选择”。
赛斯·诺布尔

不同的外壳,是的;但是不同的“系统”?真的有任何一个外壳可以$(...)在一个系统上支持但在另一个系统上不支持吗?
ruakh 2012年

4
-1,它根本不回答问题。
伯恩哈德

3
@ruakh&Seth:所有POSIX shell都支持$(…)。没有POSIX外壳(即具有纯正的Bourne外壳)的系统将非常旧。如今,即使/bin/sh是Bourne Shell且您需要另一条路径(例如/usr/xpg4/bin/sh获得POSIX Shell)的系统也很少见。向没有专业管理古代Unix Boxen的人推荐反引号对他们来说是一种伤害。
吉尔斯(Gillles)“所以-别再作恶了”
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.