文章出處

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

$ find /usr/bin -inum 376183

/usr/bin/alias

/usr/bin/bg

/usr/bin/cd

/usr/bin/command

/usr/bin/fc

/usr/bin/fg

/usr/bin/getopts

/usr/bin/hash

/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 上不需要這個,蘋果移植的時候考慮到自己的文件系統不區分大小寫,故意做了改良。 


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()