我正在编写一些代码,通过命令行浏览我的计算机(OSX 10.11.6),就像我一直这样,我写错了! (Bum-Bum-BUUUUM!)而不是输入:
cd USB
我打字
Cd USB
什么都没发生,但没有注册为无效命令。对此感到困惑,我做了一些调查:我检查了man
条目。没有入场券。我使用/usr/bin/Cd
找到了源文件(which 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有什么关系?
任何帮助都会很棒,谢谢!
答案 0 :(得分:8)
默认情况下,macOS使用不区分大小写的文件系统 [1] ,这有时会产生误导:
which Cd
在返回(有效)相同文件路径方面与which cd
和which 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在评论中指出您可以将其用作 test 是否可以更改给定目录,因为脚本的退出代码将反映出来。)
Matt's answer提供了将脚本包含在FreeBSD和OSX中的历史(主要基于FreeBSD),但值得仔细研究一下(强调我的):
来自POSIX spec:
但是,所有标准实用程序,包括表中的常规内置函数,而不是特殊内置实用程序中描述的特殊内置函数,应在一种方式,以便可以通过POSIX.1-2008的系统接口卷中定义的exec系列函数访问它们,并且可以由那些需要它的标准实用程序直接调用(env,find,nice, nohup,time,xargs)。
本质上,上述意思是:常规内置函数必须(也)可以调用独立,作为可执行文件 (无论是否为脚本或二进制文件),就像shell中的内置函数一样。
引用的常规内置插件表包含以下实用程序:
alias bg cd command false fc fg getopts jobs kill newgrp pwd read true umask unalias wait
注意:特殊内置实用程序仅限于shell-internal,它们的行为与常规内置实用程序不同。
因此, 正式符合POSIX标准的操作系统必须确实提供cd
作为外部实用程序 。
同时,POSIX规范。确实知道这些常规内置插件中至少某些 - 特别是cd
- 只有作为内置:
“由于cd
会影响当前的shell执行环境,因此始终作为常规内置shell提供。” - http://pubs.opengroup.org/onlinepubs/9699919799/utilities/cd.html
在列出的常规内置实用程序中, 某些将两者视为内置和作为外部实用程序强>:
例如,kill
需要是内置才能终止作业(这是一个shell- 内部概念),但它也可用作外部实用程序,以便通过PID终止进程。
但是,在列出的常规内置实用程序中,以下从不作为外部实用程序有意义,据我所知 Do告诉我你是否不同意 ,即使POSIX要求他们出席:
alias bg cd command fc fg getopts jobs read umask unalias
向Matt提供帮助以完成清单的提示;他还指出hash
内置的,即使它不是POSIX实用程序,也有无意义的脚本实现。
[1]正如Dave Newton在评论中指出的那样,可能格式化HFS +,macOS文件系统,在案例中敏感方式(即使大多数人坚持使用不区分大小写的默认值)。基于the answer Dave links to,以下命令将告诉您macOS文件系统是否不区分大小写:
diskutil info / | grep -iq '^\s*Name.*case-sensitive*' && echo "case-SENSITIVE" || echo "case-INsensitive"
答案 1 :(得分:3)
脚本本身是一种可移植的方法,即使使用随机的大写字母,也可以根据exec路径文件名将命令转换为等效的shell builtin
,这是最后一个{{1}后的字符串的任何部分。在/
变量中的1}}。然后,该脚本使用相同的参数运行builtin命令。
由于默认情况下OSX文件系统不区分大小写,$0
会将/usr/bin/cd
,Cd
,CD
和任何形式的cD
转换为{cd
1}} fs路径(如/
)返回shell内置命令/usr/bin/cd
。这在脚本中基本没用,因为cd
仅影响它运行的当前shell,当脚本结束时会立即关闭。
类似file exists in FreeBSD,Apple适合进行大小写转换。默认情况下,Mac文件系统不区分大小写(但保留大小写)。
cd
标头是文件中的源信息。
大多数底层OSX系统直接来自FreeBSD或基于它。基于此的Windowing系统和Cocoa应用层是OSX成为真正的Apple的地方。一些较低级别的Apple位甚至已经将其重新引入FreeBSD,如Clang和LLVM编译器。
earlier FreeBSD svn commits有点轻松:
更多的想法导致了通用脚本可以 实现任何无用的POSIX所需的``regular shell builtin'' 公用事业...
虽然大多数内置程序在通过脚本在新shell中运行时非常有用,但此合规性脚本用于命令$FreeBSD: src/usr.bin/alias/generic.sh,v 1.2 2005/10/24 22:32:19 cperciva Exp $
。 POSIX compliance is fun!
答案 2 :(得分:2)
我记得,MacOS默认使用不区分大小写的文件系统。您看到/usr/bin/Cd
的命令实际上是/usr/bin/cd
,但可以通过任一名称引用它。
您可以通过输入
来查看ls /usr/bin/ | grep -i cd
通常cd
是shell中的内置命令。如您所知,它会更改当前目录。外部cd
命令几乎无用 - 但它仍然存在。
它可用于检测是否可以更改到指定的目录而不会实际影响当前进程的工作目录。
你的shell(可能是bash)倾向于假设区分大小写的命令名。内置命令只能称为cd
,但由于它能够打开名为/usr/bin/Cd
的脚本文件,因此可以查找并执行它。