bash的工作特性之命令執(zhí)行狀態(tài)返回值和命令展開所涉及內(nèi)容

bash的工作特性之命令執(zhí)行狀態(tài)返回值

一、shell是什么?

Shell本身是一個用C語言編寫的程序,它是用戶使用Unix/Linux的橋,用戶的大部分工作都是通過Shell完成的。Shell既是一種命令語言,又是一種程序設(shè)計語言。作為命令語言,它交互式地解釋和執(zhí)行用戶輸入的命令;作為程序設(shè)計語言,它定義了各種變量和參數(shù),并提供了許多在高級語言中才具有的控制結(jié)構(gòu),包括循環(huán)和分支。
shell是一個應(yīng)用程序,是用戶管理應(yīng)用程序的一個接口。

二、廣義上shell的分類

GUI:圖形用戶界面
KDE,GNOME,XFCE
CLI:命令行接口
bash, zsh, fishsh, csh, tcsh, ksh

在大多發(fā)行版中常用的為bash

三、bash的特性

bash是弱類型的編程語言,不嚴(yán)格區(qū)分?jǐn)?shù)據(jù)類型,意味把所有數(shù)據(jù)統(tǒng)統(tǒng)當(dāng)作字符串處理;

字符串類型的數(shù)據(jù)可不加引號;

引號有三種類型:', ", `

', ":字符引用

': 強(qiáng)引用,其內(nèi)部的變量不會被替換;

":弱引用,其內(nèi)部的變量會被替換;

`:命令引用

變量引用:${NAME}

a、bash特性之一:命令別名

獲取當(dāng)前用戶可用的別名的定義:

1  # alias
定義別名:

1  # alias NAME='COMMAND'
生命周期:當(dāng)前shell進(jìn)程;

1 # unalias NAME
撤消別名:

b、bash的特性之二:命令歷史

shell進(jìn)程會保存其會話中用戶曾經(jīng)執(zhí)行過的命令;命令通過其“歷史文件”來持久保存此前執(zhí)行過的命令;每個用戶都有其自己專用的歷史文件;

HISTSIZE:shell進(jìn)程的緩沖區(qū)保留的歷史命令的條數(shù);

HISTFILESIZE:命令歷史文件可保存的歷史命令的條數(shù);

默認(rèn)均為1000;

1 # echo $HISTSIZE
2 1000
3 # echo $HISTFILESIZE
4 1000
HISTFILE:當(dāng)前用戶的命令歷史文件;

~/.bash_history

查看命令歷史列表:

1 # history
命令用法:

history -c:清空命令歷史;

history -d OFFSET:刪除指定的條目;

1 # history -d 156
-a 將當(dāng)前緩沖的歷史行追加到歷史文件中

-n 從歷史文件中讀取所有未被讀取的行

-r 讀取歷史文件并將內(nèi)容追加到歷史列表中

調(diào)用命令歷史列表中的命令以重執(zhí)行之目的:

!#:再一次執(zhí)行歷史列表中的第#條命令;

1 # history
2 ....
3 72 cat test
4 73 history
5 # !72
6 cat test
7 Hello World
!!:再一次執(zhí)行上一條命令;

1 # cat test
2 Hello World
3 # !!
4 cat test
5 Hello World

        !STRING:再一次執(zhí)行命令歷史列表中最近一個以指定的STRING開頭的命令;

1 # !cat
2 cat test
3 Hello World
調(diào)用上一條命令的最后一個參數(shù):

快捷鍵:ESC, .
Alt+.

!$:給出的字符組合

顯示最近的n條件命令歷史:

history  #

控制命令歷史的記錄方式:

通過HISTCONTROL環(huán)境變量進(jìn)行,其取值:

ignoredups:忽略重復(fù)的命令;重復(fù)是指連續(xù)且相同的令;

ignorespace:以空白字符開頭的命令不記入歷史;

ignoreboth:上述兩者同時生效;

修改變量值的方式:

NAME='VALUE'

1 # echo $HISTCONTROL
2 ignoredups
3 # HISTCONTROL="ignoreboth"
4 # echo $HISTCONTROL
5 ignoreboth

c、bash特性之三:快捷鍵

Ctrl+a:跳至命令行首;

Ctrl+e:跳至命令行尾;

Ctrl+k:刪除光標(biāo)所在處至尾部的內(nèi)容;

Ctrl+u:刪除行首至光標(biāo)所在處的內(nèi)容;

d、bash的特性之四:命令補(bǔ)全和路徑補(bǔ)全

命令補(bǔ)全:

shell程序在接收到用戶執(zhí)行命令的請求且分析完成之后,最左側(cè)字符串將被當(dāng)作命令去查找;

 查找機(jī)制:

(1) 查找內(nèi)部命令;

(2) 查找外部命令:

1、去$PATH變量所指定的各路徑下,自左而右逐個搜索各目錄下的文件名;

2、給定的打頭的字符串如果能惟一標(biāo)識某命令程序文件的文件名,則直接補(bǔ)全;

3、不能惟一標(biāo)識,再擊tab可給列表;

4、錯誤:沒有任何命令可被此打頭字符串標(biāo)識;

路徑補(bǔ)全:

在給定的起始路徑的上級目錄下,以對應(yīng)路徑下的打頭字符串來逐一匹配上級目標(biāo)下的每個文件:

惟一標(biāo)識:tab補(bǔ)全;

不能惟一標(biāo)識:tab, tab給出列表;

錯誤路徑:沒有響應(yīng);

e、bash的特性之五:命令行展開:

把命令行的給定的特殊符號自動替換為相應(yīng)字符串的機(jī)制;

~: 自動替換為用戶家目錄;

~USERNAME:自動替換為指定用戶的家目錄;

{}:可承載一個以逗號分隔的路徑列表,能夠?qū)⑵湔归_為多個獨(dú)立路徑;

    例如:
           
            /tmp/{a,b,c} /tmp/a /tmp/b /tmp/c
           
            /tmp/{a,b}/z /tmp/a/z /tmp/b/z

1 # cd ~
2 # pwd
3 /root
4 # cd ~testuser
5 testuser]# pwd
6 /home/testuser

f、bash特性之六:命令的執(zhí)行狀態(tài)結(jié)果:

命令的正常輸出結(jié)果:命令的返回值;

 通過引用來保存下來或直接調(diào)用——“命令引用”

'COMMAND'

$(COMMAND)

1 # ls -ld 'pwd'
命令的執(zhí)行狀態(tài)結(jié)果:

成功:0

失?。?-255

1 # echo "Helllo World"
2 Helllo World
3 # echo $?
4 0
5 # echoa "Hello World"
6 -bash: echoa: command not found
7 # echo $?
8 127
bash用一個特殊變量來保存最一次執(zhí)行的命令的狀態(tài)結(jié)果:

$?

bash中的引用:

'':強(qiáng)引用

"":弱引用

“:命令引用

1 # echo '$PATH'
2 $PATH
3 # echo "$PATH"
4 /usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin5 :/usr/bin:/root/bin
6 # echo 'pwd'
7 /home/testuser

g、bash的特性之七:glob

glob:文件名通配;快速引用多個文件;文件名整體匹配度檢測;
元字符:基于元字符可編寫匹配模式(pattern);

*:匹配任意長度的任意字符;

,pa,p,

p*:pa, p

?:匹配任意單個字符;

        p?, p?a, p??

p??: pa, pad, 

[ ]:匹配指定集合內(nèi)的任意單個字符;

        [a-z], [A-Z]:不區(qū)分字符大小寫;

[0-9]

    [a-z0-9]

[[:upper:]]:所有大寫字母;

[[:lower:]]:所有小寫字母;

        [[:digit:]]:所有的數(shù)字;

[[:alpha:]]:所有字母;

[[:alnum:]]:所有字母和數(shù)字;

[[:space:]]:空白字符;

[[:punct:]]:標(biāo)點(diǎn)符號;

[^ ]:匹配指定集合外的任意單個字符;

[^[:alpha:]]

測試:

1、顯示/etc目錄下,以非字母開頭,后面跟了一個字母及其它任意長度任意字符的文件或目錄;
 ls -d /etc/[^[:alpha:]][a-z]*
 
2、復(fù)制/etc目錄下,所以n開頭,以非數(shù)字結(jié)尾的文件或目錄至/tmp/etc目錄下;
mkdir /tmp/etc
cp -r /etc/n*[^0-9] /tmp/etc/

3、顯示/usr/share/man目錄下,所有以man開頭,后跟一個數(shù)字結(jié)尾的文件或目錄;
ls -d /ur/share/man/man[0-9]

4、復(fù)制/etc目錄下,所以p,m,r開頭的,且以.conf結(jié)尾的文件或目錄至/tmp/conf.d目錄下;
mkdir /tmp/conf.d/
cp -r /etc/[pmr]*.conf /tmp/conf.d/

h、bash特性之八:變量

程序:指令+數(shù)據(jù)

數(shù)據(jù):文件、變量;

變量:內(nèi)存空間,有名稱,名稱即為變量名,對應(yīng)的內(nèi)存空間中的數(shù)據(jù)即為變量的值;

變量賦值:NAME=VALUE

=:賦值符號;

把VALUE存儲到NAME指向的內(nèi)存空間中;

編程語言:

強(qiáng)類型:嚴(yán)格區(qū)分變量中的數(shù)據(jù)類型;

弱類型:不區(qū)分變量中存儲的數(shù)據(jù)類型,統(tǒng)一為字符型;

bash:統(tǒng)統(tǒng)默認(rèn)為字符型數(shù)據(jù);變量無需事先聲明;

變量為什么有類型?

存儲空間、存儲格式、參與的運(yùn)算、……

  類型不同決定對數(shù)據(jù)的處理方式不同

變量命名:只能使用字母、數(shù)字和下劃線;而且不能以數(shù)字開頭;

變量名:見名知義;不能使用程序保留字,例如if、case、then、fi、esac、for、while、until、break、continue等等;

變量引用:${NAME}, $NAME

 變量替換:把變量引用符號出現(xiàn)的位置替換為其指向的內(nèi)存空間中的數(shù)據(jù);

bash變量種類:

本地變量:作用域為當(dāng)前shell進(jìn)程;不包括其子進(jìn)程;

環(huán)境變量:使用域為當(dāng)前shell進(jìn)程及其子進(jìn)程;

局部變量

   作用域:生效范圍,也即可引用到的范圍;

位置參數(shù)變量:

特殊變量

本地變量:

變量賦值:NAME=VALUE

變量引用:$NAME, ${NAME}

""

查看變量:set

撤銷變量:unset NAME

注意:此處非為變量引用,因此不能使用$;

所有的本地變量在shell進(jìn)程終止時,會被自動撤銷;

環(huán)境變量:

變量聲明和賦值:

declare -x NAME[=VALUE]

export NAME[=VALUE]

引用方式:

${NAME}, $NAME

注意:bash內(nèi)嵌了許多環(huán)境變量,名稱為全大寫字母,例如UID、HOME、PWD、SHELL, PATH, HISTSIZE等等;

環(huán)境變量查看:

export, declare -x

env, printenv

撤銷環(huán)境變量:

unset NAME

只讀變量:常量

(1) declare -r NAME

(2) readonly NAME

不支持重新賦值,也不支持撤銷操作;

1 # declare -r username='whoami'
2 # echo $username
3 root
4 # unset username
5 -bash: unset: username: cannot unset: readonly variable

i、bash基于特性之九:I/O重定向和管道

程序的數(shù)據(jù)流有三個:

輸入數(shù)據(jù)流: <–,標(biāo)準(zhǔn)輸入(stdin),鍵盤;
輸出數(shù)據(jù)流:–>,標(biāo)準(zhǔn)輸出(stdout), 顯示器;
錯誤數(shù)據(jù)流:–>,錯誤輸出(stderr),顯示器;

fd:file descriptor,文件描述符;

stdin: 0

stdout: 1

stderr: 2

IO重定向:

輸出重定向:

重定向程序正常執(zhí)行的結(jié)果

COMMAND > /PATH/TO/SOMEFILE

覆蓋重定向:覆蓋目標(biāo)文件中的原有內(nèi)容;

COMMAND >> /PATH/TO/SOMEFILE

追加重定向:追加新產(chǎn)生的內(nèi)容至目標(biāo)文件尾部;

shell的一個功能開關(guān):

set -C

禁止覆蓋輸出重定向至已存在的文件;

注意:此時仍然可以使用“>|”至目標(biāo)文件;

set +C

關(guān)閉上述特性;

錯誤重定向:

重定向錯誤的執(zhí)行結(jié)果;

COMMAND 2> /PATH/TO/SOMEFILE

錯誤輸出覆蓋重定向;

COMMAND 2>> /PATH/TO/SOMEFILE

錯誤輸出追加重定向;

合并標(biāo)準(zhǔn)輸出與錯誤輸出流:

(1) &>, &>>

(2) COMMAND > /PATH/TO/SOMEFILE 2>&1

COMMAND >> /PATH/TO/SOMEFILE 2>&1

特殊輸出目標(biāo):/dev/null

位桶:bit bucket

特殊的輸入文件:/dev/zero

輸入重定向:

COMMAND < /PATH/FROM/SOMEFILE

tr命令:把輸出的數(shù)據(jù)當(dāng)中的字符,實現(xiàn)對位轉(zhuǎn)換,即把數(shù)據(jù)中的存在于字符集中的字符,統(tǒng)統(tǒng)轉(zhuǎn)換為字符集2中對應(yīng)的字符;

tr – translate or delete characters

tr [OPTION]… SET1 [SET2]

(1) tr SET1 SET2 < /PATH/FROM/SOMEFILE

字符轉(zhuǎn)換

1 # cat test
2 Hello World
3 # cat test |tr 'a-z' 'A-Z'
4 HELLO WORLD

(2) tr -d SET1 < /PATH/FROM/SOMEFILE

刪除

1 # cat test
2 Hello World
3 # cat test |tr -d 'ldH'
4 eo Wor

COMMAND << :

Here Document

用法:

COMMAND << EOF

COMMAND > /PATH/TO/SOMEFILE << EOF

管道:

COMMAND1 | COMMAND2 | COMMAND3 | …

練習(xí)1:把/etc/passwd文件最后三行信息中所有小寫字符改為大寫后輸出;

1 # tail -3 /etc/passwd|tr 'a-z' 'A-Z'
2 TEST1:X:5002:5002::/HOME/TEST1:/BIN/BASH
3 TEST2:X:5003:5003::/HOME/TEST2:/BIN/BASH
4 TEST3:X:5004:5004::/HOME/TEST3:/BIN/BASH

練習(xí)2:取出/etc/fstab的第6行;

1 # head -6 /etc/fstab |tail -1
2 # Accessible filesystems, by reference, are maintained under '/dev/disk'

練習(xí)3:取出/etc目錄下所有以p開頭的文件或目錄,只顯示前5個;

1 # ls -d /etc/p*|head -5
2 /etc/pam.d
3 /etc/passwd
4 /etc/passwd-
5 /etc/pinforc
6 /etc/pkcs11

tee命令:

tee – read from standard input and write to standard output and files

tee [OPTION]… [FILE]…

-a:使用追加輸出,而非覆蓋;

COMMAND | tee /PATH/TO/SOMEFILE

1 # cat test|tee /tmp/test.cat
2 Hello World
3 # cat /tmp/test.cat
4 Hello World

shell的展開

花括號展開

在非引號內(nèi)的內(nèi)容,如果用花括號包括,而且里面用逗號分隔(至少包含一個逗號,可以是空內(nèi)容),這樣花括號里的內(nèi)容會被展開成用空格分開的一個列表,花括號前后可以緊隨前綴和后綴(前后綴都是可選的)。
例如:
echo {a,b,c}
echo hello,{world,pig}
echo rep{,,,,,}eat
注意花括號展開,前綴不能是$,因為${...}在shell中是變量

波浪號展開

從波浪號~到第一個未被引號包含的斜杠/(如果沒有斜杠,則全部算上),作為波浪號前綴。
在波浪號后面的字符串作為一個可能的登錄名:如果為空,被展開成該用戶的HOME變量,如果HOME變量未設(shè)置,則用用戶執(zhí)行shell的主目錄替換。如果不為空,則按照該登錄名的主目錄替換
例如:
echo ~ # 顯示$HOME內(nèi)容
HOME=/bin && echo ~ # 顯示/bin
unset HOME && echo ~ # 顯示當(dāng)前用戶主目錄
echo ~root # 顯示root用戶主目錄

波浪號還可以與加減號和數(shù)字,產(chǎn)生一個遍歷文件夾堆棧的效果(關(guān)于文件夾堆棧,參考dirs、pushd、popd幾個命令)。
echo ~+ # 顯示$PWD
echo ~- # 顯示$OLDPWD
echo ~+2 # 顯示dirs中第3個內(nèi)容,索引基于0
echo ~-3 # 顯示dirs中倒數(shù)第4個內(nèi)容,索引基于0
如果無法展開,那就會原樣顯示,例如dir堆棧中只有1個內(nèi)容,那么+1是無法展開的(這時只有+0有效)。

Shell參數(shù)和變量展開

用$符號開始,后面接著變量名或者花括號括起來的變量名,如果是花括號內(nèi)以嘆號開頭,那么就是變量名本身。
例如:
echo $PWD # 顯示PWD對應(yīng)的值
echo ${PWD} # 顯示PWD對應(yīng)的值
echo ${!PWD} # 顯示“PWD”這個變量名,而不是它的值
echo ${!P*} # 顯示所有以P開頭的環(huán)境變量名
如果一個變量名不存在,就創(chuàng)建它。
echo ${HELLO:=hello} # 如果HELLO不存在,就用hello給它賦值,否則直接輸出$HELLO的值

算術(shù)展開

放在$(( ))中的表達(dá)式會被計算,其中變量會被求值,例如:
a=1 && b=3 && echo $(($a+$b))
如果是數(shù)字,0開頭的8進(jìn)制,0x開頭的16進(jìn)制,其它進(jìn)制用Base#number的方式
可支持2~64進(jìn)制,如果進(jìn)制小于等于36,可以用a-z或A-Z表示10-35,如果進(jìn)制大于36,則a-z表示10-35,A-Z表示36-61,@表示62,表示63
例如:
echo $((16#32)) # 16進(jìn)制的32,輸出50
echo $((64#@
)) # 輸出4031 = 62 * 64 + 63
用$[]也可以算術(shù)展開,但是不要和測試條件[]混淆了
例如:
echo $[1+4]

文件名展開

進(jìn)行字詞分隔后,如果不指定-f選項,shell會搜索"*","?","[",如果遇到了,就會認(rèn)為是一個帶pattern的word,然后用字典序?qū)⒎系乃形募鎿Q過去,如果沒有文件名匹配:1 shell的nullglob選項關(guān)閉,則不進(jìn)行文件名展開,保留word原樣;2 shell的nullglob打開,則移除這個word。如果shell的nocaseglob選項打開,則忽略大小寫。

當(dāng)匹配文件名時(這里指不包括文件夾),除非shell的dotglob被設(shè)置,否則.或./開頭的文件都必須顯示指定,例如:
ls * # 列出當(dāng)前文件夾中所有不以"."開頭的文件
ls .* # 列出當(dāng)前文件夾中所有以"."開頭的文件
當(dāng)匹配文件名時,"/"必需顯示匹配,例如:
ls ./* 和 ls .//是不同的。
其它情況下,"."和普通字符一樣,例如:
.txt和txt都可以匹配a.txt

還有一個系統(tǒng)變量GLOBIGNORE,如果一個文件名匹配了一個pattern word,但是它也匹配了GLOBIGNORE,則它會被忽略,不過兩個特殊文件一定會被忽略,就是"."和".."。
如果GLOBIGNORE打開,那么dotglob選項也會自動打開,這樣會導(dǎo)致當(dāng)你ls 時,其他以"."開頭的文件也會被match,如果想忽略"."開頭的文件,可以在GLOBIGNORE里面添加一個"."的匹配。如果GLOBIGNORE未設(shè)定,則dotglob關(guān)閉。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容