本篇文章介紹下面三個內容:
使用 dirname 命令獲取路徑名的目錄部分使用 basename 命令獲取路徑名的檔名部分使用 bash 的引數擴充套件獲取檔名的字尾名使用 dirname 命令獲取路徑名的目錄部分在 Linux 中,可以使用 dirname 命令獲取路徑名的目錄部分,不包含路徑名最後的檔名。
檢視 man dirname 的說明如下:
dirname [OPTION] NAME...
dirname - strip last component from file name.
Output each NAME with its last non-slash component and trailing slashes removed;
if NAME contains no /'s, output '.' (meaning the current directory).
即,dirname 命令可以獲取所給路徑名的目錄部分,也就是從最後一個 ‘/’ 字元往前的部分,不包括 ‘/’ 字元自身。
如果所給的路徑名沒有包含 ‘/’ 字元,返回的目錄部分是點號 ‘.’,認為是當前目錄。
所給的路徑名引數不要求是真實存在的路徑,dirname 只是對所給的路徑名字串進行處理。
dirname 命令可以提供多個路徑名引數,預設會逐行列印每個路徑名的目錄部分。
如果不想換行列印,可以使用 -z 選項,該選項的說明如下:
-z, --zero
separate output with NUL rather than newline
具體舉例如下:
$ dirname app/Phone.apk src/lib/utils.c
app
src/lib
$ dirname utils.c
.
$ dirname -z app/Phone.apk src/lib/utils.c
app src/lib $
可以看到,dirname app/Phone.apk src/lib/utils.c 命令逐行列印了所給兩個路徑名的目錄部分。
dirname utils.c 命令的路徑名引數沒有包含 / 字元,列印的目錄部分是點號 ‘.’。
dirname -z app/Phone.apk src/lib/utils.c 使用 -z 選項指定在獲取到的目錄部分後面不要加換行符,那麼列印結果都在同一行上,沒有換行。列印結果最後的 $ 字元是命令列提示符。
使用 basename 命令獲取路徑名的檔名部分在 Linux 中,可以使用 basename 命令獲取路徑名的檔名部分,不包含檔名前面的目錄路徑。
檢視 man basename 的說明如下:
basename NAME [SUFFIX]
basename OPTION... NAME...
basename - strip directory and suffix from filenames.
Print NAME with any leading directory components removed.
If specified, also remove a trailing SUFFIX.
即,basename 命令可以獲取所給路徑名的檔名部分,也就是從最後一個 ‘/’ 字元往後的部分,不包括 ‘/’ 字元自身。
當只提供一個路徑名引數時,後面可以提供一個可選的 SUFFIX 引數,該引數指定去掉檔名的字尾部分。
basename 預設只處理一個路徑名引數。
如果想要處理多個路徑名引數,需要使用 -a 選項,該選項的說明如下:
-a, --multiple
support multiple arguments and treat each as a NAME
當使用 -a 選項指定提供多個路徑名引數時,basename 會逐行列印每個路徑名的檔名部分。
如果不想換行列印,可以再使用 -z 選項,該選項的說明如下:
-z, --zero
separate output with NUL rather than newline
當提供多個路徑名引數時,如果想指定去掉檔名的字尾部分,需要用 -s 選項,該選項的說明如下:
-s, --suffix=SUFFIX
remove a trailing SUFFIX
具體舉例說明如下:
$ basename src/lib/utils.c
utils.c
$ basename src/lib/utils.c .c
utils
$ basename -s .c src/lib/utils.c
utils
$ basename -a src/lib/utils.c src/main.c
utils.c
main.c
$ basename -a -s .c src/lib/utils.c src/main.c
utils
main
$ basename -a -z src/lib/utils.c src/main.c
utils.c main.c $
可以看到,basename src/lib/utils.c 命令獲取到所給路徑名的檔名部分,也就是 utils.c。
basename src/lib/utils.c .c 命令指定從獲取到的檔名中去掉 .c 字尾,返回 utils。
而 basename -s .c src/lib/utils.c 命令通過 -s .c 指定從獲取到的檔名中去掉 .c 字尾,要在 -s 選項後面提供去掉的檔名字尾部分。
basename -a src/lib/utils.c src/main.c 命令使用 -a 選項指定處理多個路徑名,可以避免後面的檔名被當成 SUFFIX 引數,獲取到的多個檔名會逐行列印。
basename -a -s .c src/lib/utils.c src/main.c 命令通過 -a 選項指定處理多個路徑名,通過 -s .c 指定從獲取到的檔名中去掉 .c 字尾。
basename -a -z src/lib/utils.c src/main.c 命令通過 -a 選項指定處理多個路徑名,通過 -z 選項指定獲取到的檔名部分後面不要加換行符,那麼列印結果都在同一行上,沒有換行。列印結果最後的 $ 字元是命令列提示符。
使用 bash 的引數擴充套件獲取檔名的字尾名在 bash 中,可以使用引數擴充套件(parameter expansion)表示式來獲取檔名的字尾名。
具體說明如下:
${filename##*.}
這個表示式在 filename 變數值中匹配 ‘.’ 這個字元,一直到最後一次匹配為止,然後返回該字元後面的部分,也就是檔名的字尾名,不包含 ‘.’ 這個字元。
注意:${filename##*.} 這個表示式是 bash 的引數擴充套件表示式,filename 會被當成變數名處理,獲取該變數值以便進行引數擴充套件。
它不能直接處理字串,filename 不會被當成字串處理,必須把字串賦值給變數,然後把變數名放到該表示式中進行處理。
具體舉例如下:
$ echo ${src/lib/utils.c##*.}
$ filename="src/lib/utils.c"
$ echo ${filename##*.}
c
$ filename="utils.c"
$ echo ${filename##*.}
c
$ filename="utils.1.c"
$ echo ${filename##*.}
c
$ echo '.'${filename##*.}
.c
$ filename="util"
$ echo ${filename##*.}
util
可以看到,echo ${src/lib/utils.c##*.} 命令輸出為空。這裡沒有把 src/lib/utils.c 當成要處理的字串,而是當成變數名。當前沒有這個變數,變數值為空,匹配結果也為空。
當把 "src/lib/utils.c" 賦值給 filename 變數後,echo ${filename##*.} 命令打印出 filename 變數值對應字串的字尾名,也就是 c,沒有包含 . 這個字元。
修改 filename 變數值為 "utils.c",echo ${filename##*.} 命令也列印了對應的字尾名。
把 filename 變數賦值為 "utils.1.c",包含多個 ‘.’ 字元,${filename##*.} 表示式會一直匹配到最後一個 ‘.’ 字元,並返回該字元後面的部分。
由於這個表示式獲取的字尾名不包含 ‘.’ 字元,如果需要加上 ‘.’ 字元,可以在表示式前面主動加上這個字元。
例如,'.'${filename##*.} 這個寫法會在表示式返回值前面加上 ‘.’ 字元。
要注意的是,當所給變數值中沒有包含 ‘.’ 字元時,這個表示式會返回變數值自身。修改 filename 變數值為 "util",echo ${filename##*.} 命令列印了這個變數值自身。
當 ${filename##*.} 返回的值等於 $filename 的值時,說明 filename 變數值不包含 ‘.’ 字元,也就是不帶有後綴名。