每次輸入命令行按下Enter鍵時,bash都會在執行命令之前對文本進行多重處理。
首先,我們先提下echo
命令,它是shell的一個內置命令,它把文本參數內容打印到標準輸出。
例如
$ echo this is a test
this is a test
還有個例子
$ echo *
all.txt ls-error.txt ls-output.txt ls.txt test1.txt
這裏,並不是輸出“*”,而是輸出文件夾內所有文件,這是因爲“*”意味着“匹配文件名中的任意字符”.
1.擴展
1.1 路徑名擴展
通過使用通配符來實現擴展的機制成爲路徑名擴展(pathname expansion),給定以上主目錄,執行下面的擴展:
$ echo l*
ls-error.txt ls-output.txt ls.txt
$ echo *1.txt
test1.txt
$ echo /*/*/lib/
/opt/containerd/lib/ /usr/local/lib/
1.2 波浪線擴展
波浪線(~
)用在一個單詞的開頭,它將被擴展爲指定用戶的主目錄名;如果沒有指定用戶名,則擴展爲當前用戶名的主目錄.
$ echo ~
/home/lmj
如果指定用戶
$ echo ~ksl
/home/ksl
1.3 算術擴展
shell支持通過擴展來運行算術表達式,這允許我們把shell提示符當做計算器來使用。
$ echo $((2+2))
4
語法爲
$((expression))
算術擴展只支持整數(沒有小數操作),但是可以執行不同的運算,例如加、減、乘、除、取餘、取冪.
空格在算術表達式中沒有意義,且表達式可以嵌套
$ echo $(($((5**2))*3))
75
1.4 花括號擴展
花括號擴展(brace expansion),可以按照花括號裏邊的模式創建多種文本字符串,例如:
$ echo test-{1,2,3,4}.txt
test-1.txt test-2.txt test-3.txt test-4.txt
用於花括號擴展的模式信息可以包含一個稱爲前導字符(preamble)的開頭部分和一個稱爲附言(postscript)的結尾部分,花括號表達式本身可以包含一系列逗號分隔的字符串,也可以包含**一系列(兩個.)**整數或者單個字符。
例如
$ echo img{1..4}.png
img1.png img2.png img3.png img4.png
或者下面輸出一系列逆排序的字母
$ echo {Z..A}
Z Y X W V U T S R Q P O N M L K J I H G F E D C B A
花括號的嵌套,類似於循環的嵌套
$ echo A{1,2}_{3,4}B
A1_3B A1_4B A2_3B A2_4B
$ echo a{A{1,2},B{3,4}}b
aA1b aA2b aB3b aB4b
1.5 參數擴展
參數擴展(parameter expansion)的許多特性與系統存儲小塊數據以及給每個小塊數據命名的性能有關。例如命名爲USER的變量包含了你的用戶名。
$ echo $USER
lmj
可以查看可用的變量列表
$ printenv | less
包含了CUDA_HOME,PATH,PWD,HOME等常見的變量。
1.6 命令替換
命令替換可以把一個命令的輸出作爲一個擴展模式使用,例如
$ echo $(ls)
all.txt ls-error.txt ls-output.txt ls.txt test1.txt
$ ls -l $(which cp)
-rwxr-xr-x 1 root root 151024 Mar 3 2017 /bin/cp
相當於which cp返回/bin/cp,然後再ls -l /bin/cp
2. 引用
現在我們學習如何來控制擴展
$ echo The total is $100.00
The total is 00.00
這跟我們想象中的不同,原因是$1是一個未定義的變量,所以參數擴展把$1的值替換成了空白字符。引用(quoting)機制可以用來有選擇性地避免不想要的擴展。
2.1 雙引號
第一種引用類型是雙引號(double quote).如果文本放在雙引號中,那麼shell使用的所有特殊字符都將失去它們的特殊含義,而被看做普通的字符。“$”(美元符號),“\”(反斜槓),“’’”(反引號)除外.
一般來說,文件名不允許有空格,加入不幸有個文件名爲 two words.txt,可以通過雙引號來阻止單詞分割,得到預期的效果。
$ ls "two words.txt"
$ mv "two words.txt" two_words.txt
但是,參數擴展、算術擴展和命令替換在雙引號中仍有效。
$ echo "$USER $((2+2)) $(cal)"
lmj 4 June 2020
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
那麼雙引號對字符替換有什麼影響呢?默認情況下,單詞分割會先查找是否存在空格、製表符以及換行符,然後把它們當做單次的界定符(delimiter)。這意味着,沒有雙引號引起來的空格、製表符和換行符都不會被當做文本的一部分,而是被當做分隔符。
例如
$ echo this is a text
this is a text
以上命令行被識別爲命令後面跟了四個不同的參數。
$ echo "this is a text"
此時,命令行會被識別爲命令後邊跟着一個參數“text”
2.2 單引號
如果我們希望抑制所有的擴展,那麼應該使用單引號。
$ echo text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER
text /home/lixj/vpn.txt a b foo 4 lmj
$ echo "text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER"
text ~/*.txt {a,b} foo 4 lmj
$ echo 'text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER'
text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER
2.3 轉義字符
有時候我們想要引用單個字符,可以通過在該字符前加反斜槓
來實現。轉義字符經常在雙引號中用來有選擇性地阻止擴展。
$ echo "The balance for user $USER is \$50.00"
The balance for user lixj is $50.00