優質博文:IT-BLOG-CN
Linux
是一個多人多任務的環境,每個人登錄系統都能取得一個bash shell
,每個人都能夠使用bash
下達mail
這個指令來接收自己的郵箱等等。問題是,bash
如何得知你的郵箱是那個文件?這就需要『變量』的幫助。
一、什么是變量
【1】變量的可變性與方便性: 簡單的說,變量就是讓一個特定的字符串代表不固定的內容。例如,每個賬號的郵件預設是以MAIL
這個變量來進行存取的。當zzx
用戶登錄時,他便會去MAIL
這個變量,而這個變量的內容其實是/var/spool/mail/zzx
,那如果 bird登錄,他的變量MAIL
的內容就是/var/spool/mail/bird
。而我們使用信件讀取指令mail
來讀取自己的郵箱信件。
【2】影響bash
環境操作的變量: 例如PATH
變量,你能不能在任何目錄下執行某個指令,與PATH
這個變量有很大關系。例如你下達ls
這個指令時,系統就是通過PATH
這個變量里面的內容所記錄的路徑順序來搜索指令的。如果搜索完PATH
變量內的路徑還找不到ls
這個指令時,就會在屏幕上顯示『 command not found 』
的錯誤訊息了。在Linux System
下,所有的線程都是需要一個執行碼,當正確登入Linux
后,你就有一個bash
執行程序,也才真正的經由bash
來跟系統溝通。由于系統需要一些變量來提供他自己數據的存取(或者是一些環境的設定參數值,例如是否要顯示彩色等等),所以就有一些所謂的『環境變量』需要來讀入系統中,這些環境例如PATH
、HOME
、MAIL
、SHELL
等等。為了區別與自定義變量的不同,環境變量通常以大寫字符來表示。
【3】腳本程序設計(shell script)
的好幫手: 在個人設定方面,例如我們要寫一個大型script
時,有些數據可能由于用戶習慣的不同而有差異,比如說路徑,由于路徑在script
被使用的相當多,如果下次換一部主機,都要修改 script
里面的所有路徑,那一定很low
,這個時候就使用變量,而該變量的定義寫在最前面,后面相關的路徑名稱都以變量來取代,那到時候只需要修改一行就等于修改了全部路徑,相當方便。
二、變量的取用與設定
【1】變量的取用(echo)
: 利用echo
就能夠讀取變量,只需要在變量前加上$
符號,或者用${變量}
的方式讀取內容。
[root@learnVM 桌面]# echo $PATH
:/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin
[root@learnVM 桌面]# echo ${PATH}
【2】變量與變量內容之間如何設定與修改: 用等號(=)
連接變量與他的內容就好。
[root@learnVM 桌面]# echo $username <= 目前沒有查詢到任何數據,因為此變量為被設定。
[root@learnVM 桌面]# username=zzx
[root@learnVM 桌面]# echo $username
zzx <= 為我們設定的username值。
【3】變量的設定規則:
①、等號兩邊不能直接接空格符。
②、變量名稱只能是英文字母與數字,但是開頭字符不能時數字。
③、變量內容若有空格符可使用雙引號『"』
或單引號『'』
將變量內容結合起來。
[root@learnVM 桌面]# test="i am is $username" <= 雙引號的特殊字符如$等,可以保有原本的特性
[root@learnVM 桌面]# echo $test
i am is zzx <= 對$username進行了解析[root@learnVM 桌面]# test='i am is $username' <= 單引號的特殊字符,僅為一般字符,純文本。
[root@learnVM 桌面]# echo $test
i am is $username <= 不對$username進行了解析
④、可以使用跳脫字符『 \ 』
將特殊符號(如:[Enter]
,$
,\
,空格符,’ 等)
[root@learnVM 桌面]# test=i\ am\ is\ zzx
[root@learnVM 桌面]# echo $test
i am is zzx
⑤、變量值是一串指令所提供的信息時,可以使用反單引號『指令』
或『$(指令) 』
,例如想要取核心版本:
[root@learnVM 桌面]# version=`uname -r`
[root@learnVM 桌面]# echo $version
2.6.32-642.el6.x86_64
⑥、若該變量為擴展變量內容時,則可用 “$變量名稱” 或 ${變量} 累加內容,如下:
[root@learnVM 桌面]# test=i\ am\ is\ zzx
[root@learnVM 桌面]# test=${test}\ cool <= 或者使用"$test"\ cool
[root@learnVM 桌面]# echo $test
i am is zzx cool
⑦、若該變量需要在其他子程序執行,則需要export
來使變量編程環境變量:『 export 變量名 』
⑧、通常大寫的變量是系統默認的變量,自定義的變量一般都為小寫。(規則,不遵守也行)
⑨、取消變量的方法使用:unset
[root@learnVM 桌面]# unset test
[root@learnVM 桌面]# echo $test<= 變量已被取消,輸出的值為空
三、環境變量的功能
【1】用env
觀察環境變量與常見環境變量說明: 列出目前的shell
環境下的所有環境變量與其內容。
[root@learnVM 桌面]# env
ORBIT_SOCKETDIR=/tmp/orbit-root
HOSTNAME=learnVM <=這部主機的主機名
IMSETTINGS_INTEGRATE_DESKTOP=yes
SHELL=/bin/bash <=目前這個環境下,使用的shell是哪一個程序
TERM=xterm <=這個終端機使用的環境是什么類型
HISTSIZE=1000 <=記錄指令的筆數,默認支持1000
USER=root <=使用者的名稱
......
env
是environment
(環境)的簡寫,如下部分環境變量。如果使用export
也會是一樣的內容。下面對環境變量進行介紹:
● HOME
:代表用戶的家目錄。我們可以通過cd ~
去家目錄。有很多程序都可能會取用到這個變量的值。
● SHELL
:當前使用的SHELL
是哪只程序,Linux
預設使用/bin/bash
。
● MAIL
:當我們使用mail
這個指令在收信時,系統會去讀取郵件郵箱文件(mailbox)
。
● HISTSIZE
:這個與『歷史命令』有關,我們曾下達過的指令可以被系統記錄下來,而記錄的『筆數』則是由這個值來設定的。
● PATH
:就是執行文件搜索的路徑,目錄與目錄之間以冒號分割,由于文件的搜索是依序由PATH
的變量內的目錄來查詢的,所以,目錄的順序也是很重要的。
● LANG
:這個比較重要,很多訊息都會用到它,例如:當我們啟動某些 Perl 的程序語言文件時,他會主動的去分析語系數據文件,如果發現他無法解析的編碼語系,就可能產生錯誤。
● RANDOM
:隨機數的變量,目前大多數distributions
都會有隨機數生成器,那就是/dev/random
文件,在BASH
環境下,這個RANDOM
變量的內容,介于0~32767
之間。如果要去0~9
之間的數值,利用declare
宣告數值類型,如下:
[root@learnVM 桌面]# declare -i number=$RANDOM*10/32768;echo $number
2 <= 此時會隨機取0~9之間的數值
【2】用set
觀察所有變量(含環境變量與自定義變量):bash
可不只有環境變量,還有一些與bash
操作接口有關的變量,以及用戶自己定義的變量存在的。可通過set
指令查看,set
除了環境變量之外,還會將其他在bash
內的變量統統顯示出來。
[root@learnVM 桌面]# set
BASH=/bin/bash <=BASH 主程序放置路徑
BASH_VERSINFO=([0]="4" [1]="1" [2]="2" [3]="1" [4]="release" [5]="x86_64-redhat-linux-gnu") <=bash 的版本
COLUMNS=80 <=在目前的終端機環境下,使用的字段有幾個字符長度
HISTFILE=/root/.bash_history <=歷史命令記錄的放置位置,隱藏檔。
HISTFILESIZE=1000 <=存起來(與上個變量有關)的文件之指令的最大記錄筆數
HISTSIZE=1000 <=目前環境下,內存中記錄的歷史命令最大筆數
IFS=$' \t\n' <=預設的分隔符
LINES=24 <=目前終端機下的最大行數
PS1='[\u@\h \W]\$ ' <=PS1 就是我們系統的命令提示符,例如我的是=[root@learnVM 桌面]
PS2='> ' <=如果你使用逃脫符號(\)第二行以后的提示字符
【3】PS1
(提示字符的設定):命令提示符,當我們每次按下Enter
鍵去執行某個指令后,最后要在此出現提示字符時,就會去主動讀取這個變量值了,例如我本機的PS1='[\u@\h \W]\$ '
顯示的是一種特殊符號,這些特殊符號可以顯示不同的信息,每個distribution
的bash
默認的PS1
變量內容可能有差異,但不要緊,可以通過man bash
查詢PS1
的相關說明,以理解底下的一些符號的意義。
? \d
:可顯示出『星期 月 日』的日期格式,如:“Mon Feb 2”
? \H
:完整的主機名。
? \h
:僅取主機在第一個小數點之前的名字。
? \t
:顯示時間,為24
小時格式的『HH:MM:SS』
? \T
:顯示時間,為12
小時格式的『HH:MM:SS』
? \A
:顯示時間,為24
小時格式的『HH:MM』
? \@
:顯示時間,為12
小時格式的『am/pm』
? \u
:目前使用者的賬號名稱
? \v
:BASE
的版本信息
? \w
:完整的工作目錄名稱,由根目錄寫起的目錄名稱,所以僅會列出最后一個目錄名。
? \#
:下達的第幾個指令
? \$
:提示字符,如果是root
的話,提示字符為#
,否則為$
CentOS
預設的PS1
內容:PS1='[\u@\h \W]\$ '
,這個反斜杠后的數據為PS1
的特殊功能,與bash
的變量設定沒有關系,現在我們應該都清楚為什么我的命令提示符是:『root@learnVM 桌面』
,我們也可以修改自己的命令提示符:
[zzx@learnVM home]$ PS1='[\u@\h \w \A #\#]\$' <= \#表示第2次下達的命令,每執行一次命令累加1
[zzx@learnVM /home 06:34 #2]$
【4】$
(關于本shell
的PID
):錢字號本身也是個變量,表示當前Shell
的線程代號,既所謂的PID(Process ID)
。想要知道自己shell
的PID
可以通過echo $$
獲取PID
號碼。
[zzx@learnVM /home 06:34 #2]$echo $$
3405
【5】?
(關于上個執行指令的回傳值):問號也是一個特殊的變數,在 bash 中這個變量很重要,表示上一個執行的指令所回傳的值,當執行某指令時,這些指令都會回傳一個執行后的代碼。一般來說,如果成功的執行該指令,則會回傳一個0
值,如果執行過程發生錯誤,就會回傳『錯誤代碼』,一般就是以非為0
的數值來取代。
[zzx@learnVM /home 06:37 #3]$12name=ddd
bash: 12name=ddd: command not found
[zzx@learnVM /home 06:44 #4]$echo $?
127 <=錯誤代碼回傳值依據軟件而有不同,我們可以利用這個代碼來搜索錯誤的原因
【6】export
(自定義變量轉成環境變量):環境變量與自定義變量的區別,就是該變量能夠被子程序繼續引用的就是環境變量,反之則為自定義變量。簡單介紹下子程序與父程序:當登錄Linux
后,會獲取一個bash
(獨立的程序),這個程序的識別使用的是一個稱為程序標識符PID
。接下來在bash
底下所下達的任何指令都是由這個bash
所衍生的,那些被下達的指令被稱為子程序。
如上所示,我們在原本的bash
底下執行另一個bash
,結果操作的環境接口就會跑到第二個bash
去(就是子程序),原本的bash
就是sleep
這個指令運行的環境就是實現部分,若要回到原本的bash
去,就只有將第二個bash
結束掉(下達exit
或者logout
)指令。因為子程序僅會繼承父程序的環境變量,所以 bash
的自定義變量在進入子程序后就會消失,一直到離開子程序并回到原父程序后,變量才會有生效。那么如何將自定義的變量轉化為環境變量啦,就是通過export
指令實現。
[zzx@learnVM home]$ export 變量名稱
如果下達export
指令就會將所有的『環境變量』繡出來:
[zzx@learnVM home]$ export
declare -x CLASS_PATH=".:/usr/install/jvm/jdk1.8.0_121/lib/dt.jar:/usr/install/jvm/jdk1.8.0_121/lib/tools.jar:/usr/install/jvm/jdk1.8.0_121/jre/lib"
declare -x COLORTERM="gnome-terminal"
declare -x CVS_RSH="ssh"
declare -x DBUS_SESSION_BUS_ADDRESS="unix:abstract=/tmp/dbus-2vt9iZbym4,guid=3aeb40487b94bd413a26d22f0000003a"
declare -x DESKTOP_SESSION="gnome"
declare -x DISPLAY=":0.0"
declare -x GDMSESSION="gnome"
declare -x GDM_KEYBOARD_LAYOUT="us"
...........
四、影響顯示結果的語系變量(locale)
當我們使用man command
的方式去查詢某個數據的說明文件時,該說明文檔的內容可能會因為我們使用的語系不同而產生亂碼。另外,利用ls
查詢文件的時間時,也可能會有亂碼出現在時間部分。這個問題其實就是語系的問題。目前大多數的Linux
系統都支持萬國碼了,也支持大部分的國家語系。我們可以通過locale
指令查詢自己的Linux
支持多少語系。
[root@learnVM 桌面]# locale -a
zh_TW.big5 <= 大五碼的中文編碼
zh_TW.euctw
zh_TW.utf8 <= 萬國碼的中文編碼
......
正體中文語系至少支持了兩種以上的編碼,一種是目前還是很常見的big5
,另一種則是越來越熱門的utf-8
編碼。我們可以通過以下逐一設定每個語系有關的數據變量,但事實是, 如果其他語系變量都沒設置,且你有設置LANG
或者是LC_ALL
時,則其他的語系變量就會被這兩個變量所取代!這也是為什么在Linux
當中,通常說僅設定LANG
或LC_ALL
兩個變量而已。在Linux
主機的終端機接口(tty1~tty6)
的環境下,如果設定『 LANG=zh_TW.utf8 』
這個設定值生效后,使用 man 或者其他訊息輸出時,都會出現一堆亂碼,尤其是ls -l
這個參數。Linux
主機的終端機接口環境下是無法顯示像中文這么復雜的編碼文字,所以就會產生亂碼了。
[root@learnVM 桌面]# locale
LANG=zh_CN.UTF-8
LC_CTYPE="zh_CN.UTF-8"
LC_NUMERIC="zh_CN.UTF-8"
LC_TIME="zh_CN.UTF-8"
LC_COLLATE="zh_CN.UTF-8"
LC_MONETARY="zh_CN.UTF-8"
LC_MESSAGES="zh_CN.UTF-8"
LC_PAPER="zh_CN.UTF-8"
LC_NAME="zh_CN.UTF-8"
LC_ADDRESS="zh_CN.UTF-8"
LC_TELEPHONE="zh_CN.UTF-8"
LC_MEASUREMENT="zh_CN.UTF-8"
LC_IDENTIFICATION="zh_CN.UTF-8"
LC_ALL=
五、變量的有效范圍
變量也有使用的范圍,則『變量』可否被引用與export
有關。被export
后的變量為『環境變量』。為什么環境變量的數據可以被子程序所引用,是因為內存配置的關系。
? 當啟動一個shell
,操作系統會分配一記憶區塊給 shell 使用,此內存內之變量可讓子程序取用。
? 若在父程序中利用export
功能,可以讓自定義變量的內容寫到上述的記憶區塊當中(環境變量)
? 當加載另一個 shell 時,子shell
可以將父shell
的環境變量所在的記憶區塊導入自己的環境變量區塊中。
六、變量鍵盤讀取、數組與宣告(read、array、declare)
除了提到的變量設定功能,我們也可以通過鍵盤輸入。就類似于我們執行某些程序時,會提示使用這輸入“yes/no”
之類的訊息。我們還可以宣告這個變量的屬性,例如:數組或者是數字等等。
? read
:讀取來自鍵盤輸入的變量。這個指令最常被用在shell script
的撰寫當中,想要跟使用者對談就使用該指令。
[root@learnVM /]# read [-pt] variable
選項與參數:-p : 后面可以接提示符-t : 后面可以接等待的『秒數』這個比較有趣,不會一直等待使用者。范例一:讓用戶由鍵盤輸入一內容,將該內容編程名為 atest 的變量
[root@learnVM /]# read atest
this is a test <= 此時光標會等待你輸入
[root@learnVM /]# echo $atest
this is a test <= 你剛剛輸入的數據已經變成一個變量內容范例二:提示使用者 30 秒內輸入自己的大名,將該輸入字符串作為名為 named 的變量內容
[root@learnVM /]# read -p "pelse you name" -t 30 names
pelse you name zzx <= 會有提示字符
[root@learnVM /]# echo $names
zzx <= 輸入的數據又變成一個變量的內容
? declare/typeset
:宣告變量的類型。如果使用declare
后面并沒有接任何參數,那么bash
就會主動將所有的變量名稱與內容統統叫出來,就好像使用 set
一樣。
[root@learnVM /]# declare [-aixr] variable
選項與參數:
-a : 將后面名為 variable 的變量定義成為數組(array)類型
-i : 將后面名為 variable 的變量定義為整數數字(integer)類型
-x :用法與 export 一樣,就是將后面的 variable 變成環境變量。
-r : 將變量設定成為 readonly 類型,該變量不可被更改內容,也不能unset。范例一:讓sum 進行 1+2+3 的加和
[root@learnVM /]# sum=1+2+3
[root@learnVM /]# echo $sum
1+2+3
[root@learnVM /]# declare -i sum=1+2+3
[root@learnVM /]# echo $sum
6
由于在默認的情況底下bash
對于變量有幾個基本的定義:
● 變量類型默認為『字符串』,所以若不指定變量類型,則1+2
為一個『字符串』而不是『計算式』。
● bash
環境中的數值運算,預設最多僅能達到整數形態,所以1/3
結果是 0
;
如果需要非字符串類型的變量,那就得要進行變量的宣告才行。如下繼續接受declare
功能。
范例二:將sum 變為環境變量
[root@learnVM 桌面]# declare -x sum
[root@learnVM 桌面]# export |grep sum
declare -ix sum="6" <= 會出現 i 與 x 的宣告范例三:將sum 變為只讀屬性,不可更改
[root@learnVM 桌面]# declare -r sum
[root@learnVM 桌面]# sum=test
bash: sum: readonly variable <=不允許修改此屬性范例四:將sum 更改為非環境變量的自定義變量
[root@learnVM 桌面]# declare +x sum <= 將-變成+ 表示【取消】功能,這里 x 表示環境變量
[root@learnVM 桌面]# declare -p sum <= -p 可以單獨列出變量的類型
declare -ir sum="6" <= 只剩下i,r的類型,不具有x(環境變量)類型。
需要注意的是,如果不小心將變量設定為『只讀』,通常得要注銷再登入才能復原該變量的類型。
? 數組(array)
變量類型:var[index]=content
:表示數組名為var
,我們假定數組的內容為var[1]=1,var[2]=2,var[3]=3
等等,那么index
就是一些數字。
范例:設定上面提到的 var[1] ~ var[3] 的變數
[root@learnVM 桌面]# var[1]="1"
[root@learnVM 桌面]# var[2]="2"
[root@learnVM 桌面]# var[3]="3"
[root@learnVM 桌面]# echo "${var[1]},${var[2]},${var[3]}"
1,2,3
七、與文件系統及程序的限制關系(ulimit)
我們知道Linux
可以同時登陸十個人,如果同時啟動十個文件每個文件的大小約10 MBytes
,主機的內存就需要10*100*10= 10000MBytes=10GBytes
,系統就會掛點。為了要預防這個情況的發生,所以我們的bash
是可以『限制用戶的某些系統資源』的,包括可以開啟的文件數量,可以使用的CPU
時間,可以使用內存總量等等。可以用ulimit
進行設置。
[root@learnVM 桌面]# ulimit [-SHacdfltu] [配額]
選項與參數:-H : hard limit ,嚴格的設定,必定不能超過這個設定的數值;-S :soft limit ,警告的設定,可以超過這個設定值,但是若超過則有警告信息。在設定上,通常 soft 會比 hard 小,例如 soft 80,而hard 100-a :后面不接任何選項與參數,可以列出所有的限制額度-c : 當某些程序發生錯誤時,系統可能會將該程序的內存中的信息寫成文件(除錯用),這種文件就被稱為核心文件(core file)。此為限制每個核心文件的最大容量。-f : 此 shell 可以建立的最大文件容量(一般可能設定為2GB)單位為 Kbytes-d : 程序可使用的最大斷裂內存(segment)容量。-l : 可用于鎖定的內容容量-t : 可使用的最大CPU時間(單位為秒)-u : 單一用戶可以使用的最大程序(process)數量
范例:列出你目前身份(假設為一般賬號)的所有限制數據數值
[root@learnVM 桌面]# ulimit -a
core file size (blocks, -c) 0 <=只要是0就代表么有限制
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited <=可建立的單一文件大小
pending signals (-i) 7334
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024 <=同時可開啟的文件數量
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 7334
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
想要復原ulimit
的設定最簡單的方法就是注銷再登入,否則就是得要重新以 ulimit
設定才行。需要注意的是,一般身份使用者如果要以ulimit
設定-f
的文件大小,那么他『只能繼續減小文件容量,不能增加文件容量』。
八、變量內容的刪除、取代與替換(Optional)
【1】變量內容的刪除與取代: 具體舉例說明:
[root@learnVM 桌面]# test=1234567890
[root@learnVM 桌面]# echo ${test#*5} <= test是變量名稱,#表示從變量的最前面開始向右刪除,且僅刪除最短的那個
67890[root@learnVM 桌面]# echo ${test//8/44} <= 將8 替換為 44
12345674490
(*)
表示通配符,取0
到無窮多個任意字符。從上面 的案例可以看出刪除了5之前的所有元素。上面的一個 # 表示刪掉最短的那個,那么兩個 ## 表示刪除最長的那個數據。那么除了上述從前面開始刪除#
之外,還有重后面開始刪除的%
。上述取掉實例中,兩個斜線中間的是舊字符串,后面的是新字符串。那么兩個雙斜線表示的是替換所有符號條件的內容。
【2】變量的測試與內容替換: 通常我們會判斷某變量是否存在,如存在使用以有的,若不存在則給予一個常用的設定。舉例:
[root@learnVM 桌面]# echo ${username}<= 空白表示username變量不存在
[root@learnVM 桌面]# username=${username-root}
[root@learnVM 桌面]# echo $username
root <= 因為username不存在所以賦默認root值
[root@learnVM 桌面]# username=zzx <=當給其手動賦值zzx后,再是用 *-root
[root@learnVM 桌面]# username=${username-root}
[root@learnVM 桌面]# echo $username
zzx <=會發現默認的 root 不會生效
在大括號內冒號【:】
的作用,被測試的變量如果設定為空字符串時,就可以用*-root
中的root
來替換設定的空字符串的值:
變量設定方式 | str 沒有設定 | str 為空字符串 | str 已設定非為空字符串 |
---|---|---|---|
var=${str-expr} | var=expr | var= | var=$str |
var=${str:-expr} | var=expr | var=expr | var=$str |
var=${str+expr} | var= | var=expr | var=expr |
var=${str:+expr} | var= | var= | var=expr |
var=${str=expr} | str=expr var=expr | str不變 var= | str不變 var=$str |
var=${str:=expr} | str=expr var=expr | str=expr var=expr | str不變 var=$str |