/usr/bin/cd 是什麼鬼

上文中曾講到,我在個人 Mac 上發現不少和 Bash 內部命令同名的外部命令,在那 24 個外部命令中,我發現個奇怪的現象:它們中有 15 個竟然是 Shell 腳本,更奇怪的是,竟然是同一個 Shell 腳本的硬連接:html

$ find /usr/bin -inum 376183bash

/usr/bin/aliasdom

/usr/bin/bgui

/usr/bin/cd操作系統

/usr/bin/commandhtm

/usr/bin/fcblog

/usr/bin/fg進程

/usr/bin/getoptsci

/usr/bin/hashget

/usr/bin/jobs

/usr/bin/read

/usr/bin/type

/usr/bin/ulimit

/usr/bin/umask

/usr/bin/unalias

/usr/bin/wait

看看腳本的內容:

$ cat /usr/bin/cd

#!/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+"$@"}

腳本只有一行,它的做用是什麼?我分析了一下,當用戶正常輸入一個內部命令好比說 cd 時,Shell 確定會把它當成內部命令執行,只有用戶不當心把 cd 輸入成 CD,因爲 Mac 的文件系統不區分大小寫,Shell 纔會去執行這個外部的腳本。這個腳本拿到 $0 的值,也就是 /usr/bin/CD,砍掉路徑,而後把大小字母替換成小寫,也就是 cd,而後去執行 cd,同時帶上參數。但我有幾點想不通,這裏的 builtin 徹底是多餘的,${1+"$@"} 也徹底能夠簡寫成 "$@",最重要的是,執行這些腳本是幾乎沒有任何意義的,由於 Shell 腳本是在當前 Shell 進程的新起的 Shell 進程裏執行的,也就是說執行 CD / 至關於執行 bash -c 'cd /',當前 Shell 的工做目錄其實並無改變,除了 cd,其餘命令也同樣,雖然執行了,但徹底沒用,我再用 alias 和 unalias 演示一下:

$ alias 'll=ls -l'

$ Alias

$ Unalias ll

/usr/bin/Unalias: line 4: unalias: ll: not found

$ alias

alias ll='ls -l'

這麼作的出發點是什麼,輸入 CD 應該報錯纔對啊,不報錯反而執行了沒效果,多讓人困惑的行爲。

因而我在網上查了一下,發現一篇日語的文章詳詳細細的介紹了這個腳本的前因後果。原來這個腳本存在的緣由是:POSIX 標準要求操做系統要提供這 14 個內部命令對應的外部命令,以便 env、find、nice、nohup、time、xargs 這幾個外部命令調用,好比 env cd。POSIX 又爲何這麼規定,那就不知道了,但的確沒卵用啊,怪不得 Linux 就沒有遵照這個規範。

最初這個腳本誕生於 FreeBSD 上,爲何加上 builtin 和用 ${1+"$@"} 都是由於 FreeBSD 操做系統的緣由,那篇文章有講。還有最初的腳本是沒有  tr \[:upper:] \[:lower:] 這一部分的,FreeBSD 上不須要這個,蘋果移植的時候考慮到本身的文件系統不區分大小寫,故意作了改良。

相關文章
相關標籤/搜索