什么是 `Cd` 命令?

What is the `Cd` command?

我正在编写一些代码,通过命令行在我的计算机 (OSX 10.11.6) 中导航,就像我一直做的那样,但我打错了字!而不是键入:

cd USB

我输入了

Cd USB

什么都没发生,但它没有注册为无效命令。对此感到困惑,我做了一些调查:我检查了 man 条目。没有入口。我使用 which Cd 找到了源文件 (/usr/bin/Cd),然后 cat 编辑了它:

#!/bin/sh
# $FreeBSD: src/usr.bin/alias/generic.sh,v 1.2 2005/10/24 22:32:19 cperciva Exp $
# This file is in the public domain.
builtin `echo ${0##*/} | tr \[:upper:] \[:lower:]` ${1+"$@"}

这是什么,为什么会在这里?它与 freeBSD 有什么关系?

任何帮助都会很棒,谢谢!

macOS 默认使用 不区分大小写 文件系统[1] ,有时可能会产生误导:

which Cd 在返回(有效)相同文件路径方面与 which cdwhich CD 实际上相同。

令人困惑的是,尽管所有 3 个命令都引用了 相同的 文件,但它们以 保留大小写 的方式这样做,误导性地暗示文件名的实际大小写 无论您指定什么 .

作为解决方法,如果您使用 globbing(文件名扩展),您可以看到文件名的真实大小写:

$ ls "$(which Cd)"*  # could match additional files, but the one of interest is among them
/usr/bin/cd  # true case of the filename

Bash(macOS默认shell)在内部区分大小写 . 也就是说,它将cd识别为内置cd(它的内置目录更改命令)。

相比之下,由于大小写不同,它无法将 Cd 识别为

鉴于它无法将 Cd 识别为内置函数,它 会寻找 外部实用程序 (在 $PATH), 那就是它找到 /usr/bin/cd.

的时候

/usr/bin/cd 实现为 shell 脚本 几乎没用,因为作为外部实用程序,它不能影响 shell 的状态,所以它更改目录的尝试被简单地忽略了。
Keith Thompson 在评论中指出,您可以将其用作 测试 是否可以更改给定目录,因为脚本的退出代码将反映这一点)。

提供了将脚本包含在 FreeBSD 和 OSX(主要构建在 FreeBSD 上)背后的历史,但值得 仔细研究其基本原理(强调我的):

来自POSIX spec:

However, all of the standard utilities, including the regular built-ins in the table, but not the special built-ins described in Special Built-In Utilities, shall be implemented in a manner so that they can be accessed via the exec family of functions as defined in the System Interfaces volume of POSIX.1-2008 and can be invoked directly by those standard utilities that require it (env, find, nice, nohup, time, xargs).

本质上,上面的意思是:常规内置函数必须(也)是可调用的独立,因为executables(无论是脚本还是二进制文件),就像 shell.

中的内置函数一样

引用的 常规内置函数 table 包含以下实用程序:

alias bg cd command false fc fg getopts jobs kill newgrp pwd read true umask unalias wait

注意:特殊 内置实用程序根据定义 shell-仅限内部使用,它们的行为不同于常规内置实用程序。

因此,正式 POSIX 兼容 OS 必须确实提供 cd 作为外部实用程序.

同时,POSIX 规范。确实意识到至少 一些 这些常规内置函数 - 特别是 cd - 仅作为内置函数 才有意义

"Since cd affects the current shell execution environment, it is always provided as a shell regular built-in." - http://pubs.opengroup.org/onlinepubs/9699919799/utilities/cd.html

在列出的常规内置实用程序中,some 有意义 both 作为内置 作为外部实用程序:

例如 kill 需要是一个 内置 才能杀死 工作 (这是一个 shell-内部概念),但它也可用作外部实用程序,以便通过PID杀死进程。

但是,在列出的常规内置实用程序中,以下 never 作为 external 实用程序有意义,据我所知如果你不同意请告诉我 , 即使 POSIX 要求他们存在:

alias bg cd command fc fg getopts jobs read umask unalias

感谢 Matt 帮助完成列表;他还指出 hash 内置,即使它不是 POSIX 实用程序,也有一个毫无意义的脚本实现。


[1] 作为Dave Newton points out in a comment, it is possible to format HFS+, the macOS filesystem, in a case-sensitive manner (even though most people stick with the case-insensitive default). Based on the answer Dave links to,以下命令将告诉您您的 macOS 文件系统是否区分大小写:
diskutil info / | grep -iq '^\s*Name.*case-sensitive*' && echo "case-SENSITIVE" || echo "case-INsensitive"

我记得,MacOS 默认使用不区分大小写的文件系统。您看到的命令 /usr/bin/Cd 实际上是 /usr/bin/cd,但它可以用任何一个名称来引用。

您可以通过输入

来查看
ls /usr/bin/ | grep -i cd

通常cd是shell中的内置命令。如您所知,它会更改当前目录。外部 cd 命令几乎没用 -- 但它仍然存在。

它可用于检测是否可以在不实际影响当前进程的工作目录的情况下更改到指定目录。

您的 shell(可能 bash)倾向于采用区分大小写的命令名称。内置命令只能称为cd,但由于它可以打开名为/usr/bin/Cd的脚本文件,因此可以找到并执行它。

这是什么?

脚本本身是一种可移植的方式,可以根据 exec 路径文件名(即[=12=] 变量中最后一个 / 之后的字符串)。然后脚本 运行s 使用相同参数的内置命令。

由于 OSX 文件系统默认不区分大小写,/usr/bin/cd 转换 运行ning CdCDcD 和任何cd 的形式,带有 / fs 路径(如 /usr/bin/cd)返回到 shell 内置命令 cd。这在脚本中基本上是无用的,因为 cd 只影响当前 shell 它正在 运行 中,当脚本结束时它会立即关闭。

它与 freeBSD 有什么关系?

类似的 file exists in FreeBSD,Apple 对其进行了改编以进行大小写转换。 Mac 默认情况下文件系统不区分大小写(但保留大小写)。

$FreeBSD: src/usr.bin/alias/generic.sh,v 1.2 2005/10/24 22:32:19 cperciva Exp $头是文件中的源信息。

大部分底层 OSX 系统直接来自 FreeBSD 或基于它。在此之上的窗口系统和 Cocoa 应用程序层是 OSX 真正成为 Apple 的地方。一些较低级别的 Apple 位甚至像 Clang and LLVM 编译器一样回到了 FreeBSD。

为什么会在这里?

earlier FreeBSD svn commits 揭示了一些亮点:

A little bit more thought has resulted in a generic script which can implement any of the useless POSIX-required ``regular shell builtin'' utilities...

虽然大多数内置函数在通过脚本 运行 在新的 shell 中不是很有用,但此合规性脚本用于命令 alias bg cd command fc fg getopts hash jobs read type ulimit umask unalias waitPOSIX compliance is fun!