製作一款 CLI 工具是件有成就感的事!
之前在朋友圈求助過,如何快速製作一款 CLI 工具,就是命令行工具,比如 echo 這種。
票圈大神們貢獻了一大波方法,我先進行一波總結。
比如 Java 語言的 Spring Shell,可以和 SpringBoot 一起製作一款命令行工具,比如以下寫法。
@ShellComponent
public class SSHCommand {
@ShellMethod(value = "connect to remote server")
public void ssh(@ShellOption(value = "-s") String host) {
System.out.println(host);
}
}
即可支持一條 ssh 命令,並附帶 -s 參數。
shell>: ssh -s 192.168.0.3
192.168.0.3
用 java 給自己做一款這樣的小工具集,還是非常方便的。當然如果你不想使用 Spring,也有 JCommander 這樣的工具,不依賴 Spring 套件,只不過寫法就會比較醜陋。
除了 java 語言,大家推薦最多的還是 Go 語言的 Cobra 庫,官網 cobra.dev 非常簡潔。
具體大家去官網看吧,都是非常直觀明瞭的 demo,非常舒服。其他的我還沒有詳細調研過,這裏把票圈反饋都說下:
dpdk
python 的 click
C++ 的 boost
rust clap
nodejs
java common-cli 包
urfave/cli
xterm.js
cpp 的 boost
不過沒有提到 C 語言的,倒是有位讀者提到了 getopt 系列函數,這個是什麼呢?
先不說這個函數是什麼,你知道你常用的那些命令,像 echo,cp,mv 這些,都是由誰提供的麼?
這些都屬於 coreutils 工具類,比如 cp --version 就可以看到具體的版本信息。
既然這些 CLI 工具類都是 coreutils 裏的代碼,那我們看看這裏的實現方式,一定是比較優雅的。
打開 coreutils 的源碼,隨便找個命令,比如 basename.c 找到它的 main 方法,可以看到就是使用了 getopt_long 來解析的命令行參數。
那要說實現的優雅度,我們和 coreutils 裏的實現方式一樣,總歸是沒有錯的。
不過 getopt_long 具體怎麼使用呢?我們 man 一下它,就可以看到非常詳細的介紹,下面還有特別簡單的 demo,可以直接編譯運行的。
對比發現,這 demo 和 coreutils 裏的用法大體結構是一樣的,都是 while 循環裏不斷調用 getopt_long 函數解析 - 或者 -- 的參數,然後通過 switch 判斷返回值 c 的值,來執行不同的操作。
同時,將 long_options 也是就 -- 參數列表放在一個數組中,使用 required_argument 表示需要參數,no_argument 表示無需參數。
這時我有個想法,如果自己實現一套 coreutils,不但能學習到使用 C 語言製作一款優雅的 CLI 工具的方法,還能對常用 shell 命令有一個深入源碼式的瞭解,同時我們也可以改造這些命令使其具有我們自己的特性,還可以爲今後增加自己的新命令打下基礎。
同時,coreutils 裏很多命令的底層,也是需要調用 Linux 系統庫的,我們也可以對一些系統庫函數有更多的瞭解。
一舉好多的呀!開幹!
coreutils 中有個特別有趣且簡單的命令,yes,你在 Linux 命令行裏輸入 yes 按下回車,會發現它持續不斷輸出 y 在命令行中,非常快,就是這效果。
我是不是可以自己實現一套,並對其進行改造,讓它可以輸出行號,並且控制輸出的時間間隔,別那麼快。
說幹就幹,一款 dbf-yes 工具就做出來了。
它可以支持用 -n 參數表示輸出行號,用 -s 參數表示時間間隔秒數,最後跟一個參數 hehe 表示要輸出的字符是什麼。
感覺這個學習方式還是非常不錯的,涉及到的知識點不少,而且又非常有成就感,像闖關一樣把 coreutils 裏面的全部工具都實現一遍,增加自己的特性。
後續可能考慮出一個這樣的系列,通過實現一套 coreutils,講述一大堆底層的原理和使用方式,我個人覺得這方法真心不錯。
關於 dbf-yes 的源碼可以在 GitHub 上找到,點擊下方閱讀原文就可以跳轉,後續該項目會持續迭代。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/5L5h8-83g9TP-tTF18zItQ