引子: 個人工作兩年了, 一直從未總結自己所學, 本文章一是希望可以總結自己所學. 如果可以對各位有所協助, 也算是文有所用了. 這是linux演習系列的第一篇. 主要是總結自己對linux的認識. 首先從shell開始..
命令及原理: ls 在GUN代碼中, ls命令和dir,vdir兩個命令均屬於同一份代碼實現. 三個命令由變數ls_mode變數控制. 在ls的檔案開頭有基於ls_mode的宏定義, 可以看到不同的取值 對應不同的命令.
#define PROGRAM_NAME (ls_mode == LS_LS ? "ls" \ : (ls_mode == LS_MULTI_COL \ ? "dir" : "vdir"))
ls命令運行時的顏色控制, 主要依賴與LS_COLORS環境變數. ls源碼的入口調用了parse_ls_color函數. 該函數的主要功能為"解析LS_COLORS環境變數", 供ls的輸出做顏色控制.
if ((p = getenv ("LS_COLORS")) == NULL || *p == '\0') return;
值得說明的是, 即使LS_COLORS變數有值並不等於 ls命令輸出時一定有顏色, 該變數只是進行顏色的配置, 而不是顏色的使用. LS_COLORS變數主要指定檔案類型以及對應的顏色值, 列印其值便可一窺究竟.
[nobody@myseo ~]$ echo $LS_COLORSno=00:fi=00:di=00;34:ln=00;36:pi=40;33:so=00;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=00;32:*.cmd=00;32:*.exe=00;32:*.com=00;32:*.btm=00;32:*.bat=00;32:*.sh=00;32:*.csh=00;32:*.tar=00;31:*.tgz=00;31:*.arj=00;31:*.taz=00;31:*.lzh=00;31:*.zip=00;31:*.z=00;31:*.Z=00;31:*.gz=00;31:*.bz2=00;31:*.bz=00;31:*.tz=00;31:*.rpm=00;31:*.cpio=00;31:*.jpg=00;35:*.gif=00;35:*.bmp=00;35:*.xbm=00;35:*.xpm=00;35:*.png=00;35:*.tif=00;35:
何時輸出顏色, 由ls命令自行判斷, 判斷依據有兩個: --color的取值, 以及輸出控制代碼是否是終端(isatty函數判斷輸出控制代碼是否為tty, 當ls的輸出被重新導向時, 該函數返回false).
case COLOR_OPTION: { int i; if (optarg) i = XARGMATCH ("--color", optarg, color_args, color_types); else /* Using --color with no argument is equivalent to using --color=always. */ i = color_always; print_with_color = (i == color_always || (i == color_if_tty && isatty (STDOUT_FILENO))); if (print_with_color) { /* Don't use TAB characters in output. Some terminal emulators can't handle the combination of tabs and color codes on the same line. */ tabsize = 0; } break; }
這也就是為何ls命令非常智能, 在任何環境下都非常友好的輸出. PS: 苦惱於自訂shell顏色輸出的碼農們可以借鑒於此. --color參數的取值範圍可以從代碼中看到, 常用的為tty, none, auto; 仔細研究代碼還可以發現, 部分參數值如force等, 主要是為了相容性而保留的.
static char const *const color_args[] ={ /* force and none are for compatibility with another color-ls version */ "always", "yes", "force", "never", "no", "none", "auto", "tty", "if-tty", NULL};
ls命令擷取目錄下項目資訊的方式非常簡單, 利用的是標準C介面, 函數opendir. 函數返回dirent結構體, 其中包含了非常豐富的檔案中繼資料. 包括檔案名稱, 大小, 許可權, 所屬等等. 程式碼片段摘要重要部分, 給出如下, 粗略瀏覽即可知道其中的主要思路.
DIR *dirp; struct dirent *next; errno = 0; dirp = opendir (name); if (format == long_format || print_block_size) { p = human_readable (total_blocks, buf, human_output_opts, ST_NBLOCKSIZE, output_block_size); DIRED_FPUTS (p, stdout, strlen (p)); DIRED_PUTCHAR ('\n'); } if (cwd_n_used) print_current_files ();
關於LS命令, 先總結在這裡. 下一篇 ldd