不知道大家還記不記得有一個指令叫做 which
,它可以用來找某個指令在哪裡,譬如說 which ls
可以找到 ls
是放在 /bin/ls
但如果是 alias 的指令怎麼辦?在 zsh 裡面他會跟你說這個指令被 alias 成什麼,譬如說我的 gst
是被 alias 成 git status
這也是為什麼一直拖到現在才實作這個指令,因為前幾天才剛把 alias 做完
大家想一想,which
如果想要知道 gst
被 alias 成什麼指令,那他就一定得去查 Alias Table,但因為 Alias Table 只有 Shell 才知道,其他 Process 根本不知道 Alias Table 裡面的對應關係,所以 which
也必須以 Shell 內建指令的方式實作
如果在 zsh 中用 which
來查 which
在哪裡,也會看到他是個內建指令
which
的輸出結果大致上可以分成這三種:
如果指令有在 Alias Table 裡面,譬如說 gst
,那就輸出 gst: aliased to git status
PATH
裡面如果指令沒有在 Alias Table 裡面,譬如說 ls
,那就到 PATH
裡面找找看 ls
在哪裡,並輸出 ls: /bin/ls
如果連 PATH
裡面都找不到指令,譬如說 gggg
,那就是沒有這個指令,輸出 gggg NOT FOUND
LookPath
會在 PATH
裡面尋找檔案,譬如說 LookPath("ls")
就會得到 /bin/ls
,如果找不到的話則會回傳錯誤
lookCommand
我們要根據上面的 which 流程實作一個 lookCommand
,他會分別到 Alias Table 跟 PATH
裡面找指令並且輸出
func lookCommand(cmd string) {
// 先到 Alias Table 裡面找找看指令(gst)
value := aliasTable[cmd]
// 如果找到的話就輸出 gst: aliased to git status
// 沒找到的話就繼續往下走
if value != "" {
fmt.Printf("%s: aliased to %s\n", cmd, value)
return
}
// 到 PATH 裡面找找看指令(ls)
value, err := exec.LookPath(cmd)
// 找到的話就輸出 ls: /bin/ls
// 沒找到的話就繼續往下走
if err == nil {
fmt.Printf("%s: %s\n", cmd, value)
return
}
// Alias Table 跟 PATH 都找不到這個指令(gggg)
// 直接輸出 gggg NOT FOUND
fmt.Printf("%s NOT FOUND\n", cmd)
}
接著到 execInput
裡面加上這段
func executeInput(input string) error {
// ...
// 如果使用者下的指令是 which 開頭
// 譬如說 which gst ls gggg
if args[0] == "which" {
// 那就把 gst, ls, gggg 依序傳到 lookCommand 裡面
// 讓他跑上面的 which 流程
for _, cmd := range args[1:] {
lookCommand(cmd)
}
return nil
}
// ...
}
先把 gst
設定成 git status
,再看看 gst
、ls
、gggg
三個指令分別在哪裡
今天自己用之前寫好的 Alias Table 跟 Go 提供的 LookPath
實作了 which
指令,有沒有覺得很有趣呢?如果有什麼問題歡迎在下方留言,沒問題的話明後兩天要來講好用的 Wildcard(萬用字元) 囉