Linux基礎學習-Shell變量的豐富功能

一  Shell變量的取用與設定,變量規則


  由於系統需要一些變量來提供他數據的存取,所以就有一些所謂的『環境變量』 需要來讀入系統中了!這些環境變量例如 PATH、HOME、MAIL、SHELL。爲了區別與自訂變量的不同,環境變量通常以大寫字符來表示。 
  利用 echo 這個指令來取用變量, 變量在被取用時,前面必須要加上 $ 才行:

  [root@linux ~]# echo $variable

     [root@linux ~]# echo $PATH

  /bin:/sbin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/X11R6/bin

    [root@linux ~]# echo ${PATH}

    利用 ehco 就能夠讀出,只是需要在變量名稱前面加上 $ , 或者是以 ${variable} 的方式來取用!


例題一:請在屏幕上面顯示出您的環境變量 HOME 與 MAIL:

    echo $HOME echo $MAIL

舉例來說: 我要將 myname 這個變量名稱的內容設定爲 VBird ,那麼:

[root@linux ~]# echo $myname
<==這裏並沒有任何數據~因爲這個變量尚未被設定!是空的!
[root@linux ~]# myname=VBird
[root@linux ~]# echo $myname
VBird <==出現了!因爲這個變量已經被設定了!

當一個變量名稱尚未被設定時,預設的內容是『空』的。 另外,變量在設定時,還是需要符合某些規定的:(非常重要的規則

1. 變量與變量內容以等號『=』來連結;
2. 等號兩邊不能直接接空格符;
3. 變量名稱只能是英文字母與數字,但是數字不能是開頭字符;


4. 若有空格符可以使用雙引號『 " 』或單引號『 ' 』來將變量內容結合起來,但須要特別留意, 雙引號內的特殊字符可以保有變量特性,但是單引號內的特殊字符則僅爲一般字符;


5. 必要時需要以跳脫字符『 \ 』來將特殊符號 ( 如 Enter, $, \, 空格符, ' 等 ) 變成一般符號


6. 在一串指令中,還需要藉由其它的指令提供的信息,可以使用 quote 『 ` command` 』;(特別特別注意,那個 ` 是鍵盤上方的數字鍵 1 左邊那個按鍵,而不是單引號!)


7. 若該變量爲擴增變量內容時,則需以雙引號及 $變量名稱 如:『 "$PATH":/home』繼續累加內容;


8. 若該變量需要在其它子程序執行,則需要以 export 來使變量變成環境變量, 如『export PATH』;


9. 通常大寫字符爲系統預設變量,自行設定變量可以使用小寫字符,方便判斷 ( 純粹依照使用者興趣與嗜好 ) ;


10. 取消變量的方法爲:『unset 變量名稱』。



範例一:設定一變量 name ,且內容爲 VBird 。
[root@linux ~]# 12name=VBird
-bash: 12name=VBird: command not found <==屏幕會顯示錯誤!因爲不能以數字開頭!
[root@linux ~]# name = VBird <==還是錯誤!因爲有空白!
[root@linux ~]# name=VBird <==OK 的啦!


範例二:承上題,若變量內容爲 VBird's name 呢?
[root@linux ~]# name=VBird's name
# 因爲單引號可以將 Enter 這個特殊字符取消,所以,您可以繼續在下一行輸入內容~
# 不過,這與我們要達到的功能不同,所以,算是失敗的啦!
[root@linux ~]# name="VBird's name" <==OK 的啦!
[root@linux ~]# name=VBird\'s\ name
利用反斜線 (\) 跳脫特殊字符,例如單引號與空格鍵,這也是 OK 的啦!


範例三:我要在 PATH 這個變量當中『累加』:/home/dmtsai/bin 這個目錄
[root@linux ~]# PATH=$PATH:/home/dmtsai/bin
[root@linux ~]# PATH="$PATH":/home/dmtsai/bin
# 上面這兩種格式在 PATH 裏頭的設定都是 OK 的!但是底下的例子就不見得囉!


範例四:呈範例三,我要將 name 的內容多出 "yes" 呢?
[root@linux ~]# name=$nameyes
# 知道了吧?如果沒有雙引號,那麼變量成了啥?name 的內容是 $nameyes 這個變量!
# 呵呵!我們可沒有設定過 nameyes 這個變量吶!所以,應該是底下這樣纔對!
[root@linux ~]# name="$name"yes
[root@linux ~]# name=${name}yes


範例五:如何讓我剛剛設定的 name=VBird 可以用在下個 shell 的程序?
[root@linux ~]# name=VBird
[root@linux ~]# bash <==進入到所謂的子程序
[root@linux ~]# echo $name <==嘿嘿!並沒有剛剛設定的內容喔!
[root@linux ~]# exit <==離開剛剛的子程序
[root@linux ~]# export name
[root@linux ~]# bash <==進入到所謂的子程序
[root@linux ~]# echo $name <==出現了設定值了!
[root@linux ~]# exit <==離開剛剛的子程序
什麼是『子程序』呢?就是說,在我目前這個 shell 的情況下,
# 去啓用另一個新的 shell ,新的那個 shell 就是子程序啦!在一般的狀態下,
# 父程序的自訂變量是無法在子程序內使用的。但是透過 export 將變量變成
# 環境變量後,就能夠在子程序底下應用了!


範例六:如何進入到您目前核心的模塊目錄?
[root@linux ~]# cd /lib/modules/`uname -r`/kernel
# 每個操作系統核心版本都不相同,以 FC4 爲例,他的預設核心版本是
# 2.6.11-1.1369_FC4 所以,他的模塊目錄在 /lib/modules/2.6.11-1.1369_FC4/kernel 。
# 因爲每個 distributions 的這個值都不相同,但是我們卻可以利用 uname -r 這個指令
# 先取得版本信息,所以囉,就可以透過上面指令當中的內含指令 `uname -r`
# 先取得版本輸出到 cd .. 那個指令當中,就能夠順利的進入目前核心的驅動程序所放置
# 的目錄囉!很方便吧!


範例七:取消剛剛設定的 name 這個變量內容
[root@linux ~]# unset name


根據上面的案例你可以試試看!就可以瞭解變量的設定囉!這個是很重要的呦!請勤加練習!! 其中,較爲重要的一些特殊符號的使用囉!例如單引號、雙引號、跳脫字符、錢字號、quote 符號等等,底下的例題想一想吧!




例題二:在變量的設定當中,單引號與雙引號的用途有何不同? 

單引號與雙引號的最大不同在於雙引號仍然可以保有變量的內容,但單引號內僅能是一般字符 ,而不會有特殊符號。我們以底下的例子做說明:假設您定義了一個變量, name=VBird ,現在想以 name 這個變量的內容定義出 myname 顯示 VBird its me 這個內容,要如何訂定呢?

[root@linux ~]# name=VBird 
[root@linux ~]# echo $name 
              VBird 

[root@linux ~]# myname="$name its me" 
[root@linux ~]# echo $myname 
              VBird its me 

[root@linux ~]# myname='$name its me' 
[root@linux ~]# echo $myname 
              $name its me
使用了單引號的時候,那麼 $name 將失去原有的變量內容, 僅爲一般字符的顯示型態而已!這裏必需要特別小心在意!



例題三:在指令下達的過程中, quote ( ` ) 這個符號代表的意義爲何?

在一串指令中,在 ` 之內的指令將會被先執行,而其執行出來的結果將做爲外部的輸入信息!例如 uname -r 會顯示出目前的核心版本,,你可以先執行 uname -r 找出核心版本,然後再以『 cd 目錄』到該目錄下,當然也可以執行如同上面範例六的執行內容囉。 

另外再舉個例子,我們也知道, locate 指令可以列出所有的相關檔案檔名,但是, 如果我想要知道各個檔案的權限呢?舉例來說,我想要知道每個 crontab 相關檔名的權限:

[root@linux ~]# ls -l `locate crontab`

如此一來,先以 locate 將文件名數據都列出來,再以 ls 指令來處理的意思啦!












二  環境變量的功能,一些重要的環境變量,set,export


環境變量可以幫我們達到很多功能~包括家目錄的變換啊、提示字符的顯示啊、執行文件搜尋的路徑啊等等的, 目前我的 shell 環境中, 有多少變量啊?我們可以利用兩個指令來查閱,分別是 env 與 export 



1) 一些環境變量的說明: env


範例一:列出目前的 shell 環境下的所有環境變量與其內容。


[root@linux ~]# env

HOSTNAME=linux.dmtsai.tw <== 這部主機的主機名稱
SHELL=/bin/bash <== 目前這個環境下,使用的 Shell 是哪一個程序?
TERM=xterm <== 這個終端機使用的環境是什麼類型
HISTSIZE=1000 <== 這個就是『記錄指令的筆數』在 FC4 預設可記錄 1000 筆
USER=root <== 使用者的名稱啊!

LS_COLORS=no=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;3
1:*.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: <== 一些顏色顯示

ENV=/root/.bashrc <== 使用的個人環境設定檔
MAIL=/var/spool/mail/root <== 這個使用者所取用的 mailbox 位置
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin:/usr

/local/sbin:
/root/bin <== 不再多講啊!是執行文件指令搜尋路徑
INPUTRC=/etc/inputrc <== 與鍵盤按鍵功能有關。可以設定特殊按鍵!
PWD=/root <== 目前使用者所在的工作目錄 (利用 pwd 取出!)
LANG=en_US.UTF-8 <== 這個與語系有關,底下會再介紹!
HOME=/root <== 這個使用者的家目錄啊!
_=/bin/env <== 上一次使用的指令的最後一個參數(或指令本身)


env 是 environment (環境) 的簡寫啊~ 上面的例子當中,是列出來所有的環境變量。當然,如果使用 export 也會是一樣的內容~ 只不過, export 還有其它額外的功能就是了,我們等一下再提這個 export 指令。 那麼上面這些變量有些什麼功用呢?底下我們就一個一個來分析分析

    HOME : 代表使用者的家目錄。還記得我們可以使用 cd ~ 去到使用者的家目錄嗎?或者利用 cd 就可以直接回到使用者家目錄了。 有很多程序都可能會取用到這個變量的值喔!

    SHELL : 告知我們,目前這個環境使用的 SHELL 是哪支程序? 如果是 bash 的話,預設是 /bin/bash 的啦!

    HISTSIZE : 這個與『歷史命令』有關,亦即是, 我們曾經下達過的指令可以被系統記錄下來,而記錄的『筆數』則是由這個值來設定的。

    ENV : 這個使用者所使用的個人化環境設定檔的讀取檔案。

    MAIL : 當我們使用 mail 這個指令在收信時,系統會去讀取的郵件信箱檔案 (mailbox)。

    PATH : 就是執行文件搜尋的路徑啦~目錄與目錄中間以冒號(:)分隔, 由於檔案的搜尋是依序由 PATH 的變量內的目錄來查詢,所以,目錄的順序也是重要的喔。

    LANG : 這個重要!就是語系檔案囉~很多數據都會用到他

    RANDOM : 這個玩意兒就是『隨機隨機數』的變量啦! 我們可以透過這個隨機數檔案相關的變量 ($RANDOM)來隨機取得隨機數值喔。



2) 其它所有的變量說明: set


而除了這些環境變量之外,還有沒有什麼重要的變量呢?我們在 bash 的環境下,其實還有一些挺重要的變量,這些變量是『在這個 shell 環境下有效』的, 如果是在『子程序』,這些變量值就不會相同了。 set 這個指令除了會將環境變量列出來之外,其它我們的自訂變量,與所有的變量,都會被列出來:


[root@linux ~]# set

BASH=/bin/bash <== bash 的主程序放置路徑
BASH_VERSINFO=([0]="3" [1]="00" [2]="16" [3]="1" [4]="release"
[5]="i386-redhat-linux-gnu") <== bash 的版本啊!
BASH_VERSION='3.00.16(1)-release' <== bash 的版本啊!
COLORS=/etc/DIR_COLORS.xterm <== 使用的顏色紀錄檔案
COLUMNS=115 <== 在目前的終端機環境下,使用的字段有幾個字符長度
HISTFILE=/root/.bash_history <== 歷史命令記錄的放置檔案,隱藏檔
HISTFILESIZE=1000 <== 存起來(與上個變量有關)的檔案之指令的最大紀錄筆數。
HISTSIZE=1000 <== 目前環境下,可記錄的歷史命令最大筆數。
HOSTTYPE=i386 <== 主機安裝的軟件主要類型。我們用的是 i386 兼容機器軟件
IFS=$' \t\n' <== 預設的分隔符
LINES=35 <== 目前的終端機下的最大行數
MACHTYPE=i386-redhat-linux-gnu <== 安裝的機器類型
MAILCHECK=60 <== 與郵件有關。每 60 秒去掃瞄一次信箱有無新信!
OLDPWD=/home <== 上個工作目錄。我們可以用 cd - 來取用這個變量。
OSTYPE=linux-gnu <== 操作系統的類型!
PPID=20046 <== 父程序的 PID (會在後續章節才介紹)
PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME%%.*}:${PWD/#$HOME/~}\007"'
<== 上面這個是命令提示字符!與底下也有關。
PS1='[\u@\h \W]\$ ' <== PS1 就厲害了。這個是命令提示字符,也就是我們常見的
[root@linux ~]# 或 [dmtsai ~]$ 的設定值啦!可以更動的!
RANDOM=13586 <== 隨機數啊!上面已經提過囉~
SUPPORTED=zh_TW.UTF-8:zh_TW:zh:en_US.UTF-8 <== 本系統所支持的語系
name=VBird <== 剛剛設定的自訂變量也可以被列出來喔!
$ <== 目前這個 shell 所使用的 PID
? <== 剛剛執行完指令的回傳值。


    一般來說,不論是否爲環境變量,只要跟我們目前這個 shell 的操作接口有關的變量, 通常都會被設定爲大寫字符,也就是說,『基本上,在 Linux 預設的情況中,使用{大寫的字母}來設定的變量一般爲系統內定需要的變量』。 使用 set 除了會將系統的默認值秀出來之外,連帶的所有的你自己設定的變量也會被秀出來! 同時需要注意的是,若當時有相當多人同時在在線的話,那麼 你的變量只能給自己使用 ( 除非改的是系統的預設參數檔,如 /etc/profile ),而不會干擾到別人的!就如同前面所說的, 由於你登入 Linux 之後會取得一個 PID ,而你的設定將只對這個 PID 與子程序有關!此外, 這次登入所進行的變量設定,如果沒有更動到設定檔, 那麼這次設定的變量在下次登入時將被取消掉 ( 因爲程序 PID 不見囉! ) !所以囉, 如果你想要你的變量每次都能在你登入的時候自動就設定好了,那麼就必須將你的設定寫入登入時加載的設定檔! ( 更多的程序相關的說明,不要急~我們會在後面的 程序與資源管理 當中好好的提一提的! ) OK!OK!那麼上頭那些變量當中,有哪些是比較重要:


PS1:(提示字符的設定) 

  這個東西就是我們的『命令提示字符』啊! 當我們每次按下 [Enter] 按鍵去執行某個指令後,最後要再次出現提示字符時, 就會主動去讀取這個變數值了。上頭 PS1 內顯示的是一些特殊符號,每個版本 bash 的 PSI 變量內的特殊符號可能有些許的差異, 你應該主動的以 man bash 去查詢一下相關的變數。底下我列出 FC4 的環境下, 預設的bash 的 PS1 變量內的特殊符號代表意義:

o \d :代表日期,格式爲 Weekday Month Date,例如 "Mon Aug 1"
o \H :完整的主機名稱。舉例來說,鳥哥的練習機 linux.dmtsai.tw ,那麼這個主機名稱就是 linux.dmtsai.tw
o \h :僅取主機名稱的第一個名字。以上述來講,就是 linux 而已, .dmtsai.tw 被省略。
o \t :顯示時間,爲 24 小時格式,如: HH:MM:SS
o \T :顯示時間,12 小時的時間格式!
o \A :顯示時間,24 小時格式, HH:MM
o \u :目前使用者的賬號名稱;
o \v :BASH 的版本信息;
o \w :完整的工作目錄名稱。家目錄會以 ~ 取代;
o \W :利用 basename 取得工作目錄名稱,所以僅會列出最後一個目錄名。
o \# :下達的第幾個指令。
o \$ :提示字符,如果是 root 時,提示字符爲 # ,否則就是 $ 囉~


OK!所以,由預設的 PS1 內容爲: '\[\u@\h \W\]\$ ' 就可以瞭解爲何我們的提示字符會是: [root@linux ~]# 了吧!好了,那麼假設我想要有類似底下的提示字符:

  [root@linux /home/dmtsai 16:50 #12]#

,那個 # 代表第 12 次下達的指令。 那麼應該如何設定 PS1 呢?可以這樣啊:

[root@linux home]# PS1='[\u@\h \w \A #\#]\$ '
[root@linux /home 17:02 #85]#

# 看到了嗎?提示字符變了!變的很有趣吧!其中,那個 #85 比較有趣,
# 如果您按下 [Enter] 後,該數字就會增加喔!爲啥?上面有說明


$:(關於本 shell 的 PID) 

  其實這個咚咚代表的是『目前這個 Shell 的執行緒代號』,亦即是所謂的 PID (Process ID)。 更多的程序觀念,我們會在第四章的時候提及。想要知道我們的 shell 的 PID ,就可以: echo $$ 即可!


?:(關於上個執行指令的回傳碼) 

  問號也是一個特殊的變數?沒錯!在 bash 裏面這個變量可重要的很! 這個變數是:『上個執行的指令所回傳的值』, 上面這句話的重點是『上一個指令』與『回傳值』兩個地方。當我們執行某些指令時, 這些指令都會回傳一個執行後的代碼。一般來說,如果成功的執行該指令, 則會回傳一個 0 值,如果執行過程發生錯誤,就會回傳『錯誤代碼』纔對!一般就是以非爲 0 的數值來取代。 我們以底下的例子來看看:

[root@linux ~]# echo $SHELL
/bin/bash
[root@linux ~]# echo $?
0
# 因爲上個指令執行過程中,並沒有錯誤,爲成功的執行完畢,所以回傳 0 。
[root@linux ~]# 12name=VBird
-bash: 12name=VBird: command not found
[root@linux ~]# echo $?
127
# 發生錯誤啦!所以 echo $? 時,就會出現錯誤的代碼!
# 我們可以利用這個代碼來搜尋錯誤的原因喔!
[root@linux ~]# echo $?
0
# 咦!怎麼又變成正確了?這是因爲 "?" 只與『上一個執行指令』有關,
# 所以,我們上一個指令是執行『 echo $? 』,當然沒有錯誤,所以是 0 沒錯!


OSTYPE, HOSTTYPE, MACHTYPE:(主機硬件與核心的等級)

  這幾個東西與程序的安裝有關。我們在『Linux 主機規劃』 裏面提到過關於主機的等級方面的問題,當我們在安裝軟件的時候, 需要透過編譯器來將原始碼編譯成爲二進制的檔案 (binary file)。但是, 我們可以針對硬件的配備來進行編譯的最佳化,此時,這些參數就可以被用到了! 基本上,目前主要的 distribution 都是針對 i386 亦即最低等級的機器進行最佳化, 這樣才能夠安裝在較高階的機器上,如果以 686 的機型來最佳化, 那麼,可就無法向下兼容的喔!(早期的 OpenLinux 是針對 686 機器來釋出軟件, 所以,當時的 OpenLinux 是無法安裝在 P-166 的機器上的。 )





3) 自訂變量轉成環境變量: export


好了,上面我們環境變量也提過了,一些自訂變量也提過了,那麼,這兩者有啥不同? 他的不同處,我們在 變量設定規則 當中稍微提過, 主要是由於變量可否被子程序所引用。 當你取得一個 bash 之後,亦即得到了一個程序了,但是若你再次的執行一次 bash ,那麼你將進入『子程序』,這個程序的概念我們在資源管理章節中再詳談,這裏您先有個概念即可。 那麼由於您已經進入了該子程序,所以在父程序中的自訂變量設定將不再繼續的存在。 會存在子程序中的,僅有『環境變量』


export 變數

這個東西用在『引用他人的檔案或者其它程序』時,相當的重要的! 尤其像鳥哥常常兩三個檔案互相引用來引用去的,如果忘記設定 export 的話,那麼不同的檔案中的相同變量值,將需要一再地重複設定才行!所以,我只要在頭一個檔案使用 export 的話,那麼後續的檔案引用時,將會把該變量內容讀進來!好用的很,如果僅下達 export 而沒有接變量時,那麼此時將會把所有的『環境變量』秀出來喔!例如:

[root@linux ~]# export
declare -x ENV="/root/.bashrc"
declare -x HISTSIZE="1000"
declare -x HOME="/root"
declare -x HOSTNAME="linux.dmtsai.tw"
declare -x INPUTRC="/etc/inputrc"
declare -x LANG="en_US.UTF-8"
declare -x MAIL="/var/spool/mail/root"
declare -x SHELL="/bin/bash"
# 很多都直接省略了!不然....重複性太高,浪費版面~ ^_^












三  語系檔案的變量 (locale)


 那麼我們的 Linux 到底支持了多少的語系呢?這可以由 locale 這個指令來查詢到喔!

[root@linux ~]# locale -a
aa_DJ
aa_DJ.iso88591
en_US
en_US.iso88591
en_US.iso885915
en_US.utf8
zh_TW
zh_TW.big5
zh_TW.euctw
zh_TW.utf8

# 其實輸出的內容有很多,鳥哥將一些信息捨棄了~
# 從上面的輸出中,我們也不難看出,系統是有支持 big5, utf8 等中文語系數據的!中文語系至少支持了兩種以上的編碼,一種是目前還是很常見的 big5 ,另一種則是越來越熱門的 utf-8 編碼。 那麼我們如何修訂這些編碼呢?其實可以透過底下這些變量的說:

[root@linux ~]# LANG <==主語言的環境
[root@linux ~]# LC_CTYPE <==字符辨識的編碼
[root@linux ~]# LC_NUMERIC <==數字系統的顯示訊息
[root@linux ~]# LC_TIME <==時間系統的顯示數據
[root@linux ~]# LC_COLLATE <==字符串的比較與排序等
[root@linux ~]# LC_MONETARY <==幣值格式的顯示等
[root@linux ~]# LC_MESSAGES <==訊息顯示的內容,如菜單、錯誤訊息等
[root@linux ~]# LC_ALL <==語言環境的整體設定。


基本上,你可以逐一設定每個與語系有關的變量數據,當我們使用 locale 時,系統是列出目前 Linux 主機內保有的語系檔案, 這些語系檔案都在:/usr/lib/locale/ 這個目錄中。 但是,目前的這個 shell 環境所支持的語系,則是要看 SUPPORTED這個變數纔對喔! 那麼,如果我想要修訂系統的語系支持呢?/etc/sysconfig/i18n 這個檔案呢:

[root@linux ~]# vi /etc/sysconfig/i18n
LANG="en_US.UTF-8"
SYSFONT="latarcyrheb-sun16"
SUPPORTED="zh_TW.UTF-8:zh_TW:zh:en_US.UTF-8"











四   變量的有效範圍


  如果在跑程序的時候,有父程序與子程序的不同程序關係時, 則『變量』可否被引用是 export 有關。被 export 後的變量,我們可以稱他爲『環境變量』! 環境變量可以被子程序所引用,但是其它的自訂變量內容就不會存在於子程序中。也就是說: 我們自行設定的變量,只在目前這個 shell 環境當中存在, 在子程序中將不會存在此一變量。除非使用 export 將自訂變量變成環境變量。

  其實除了 shell 的父、子程序外,在腳本( scripts )的編寫當中,由於有的軟件會使用到 2 個以上的 scripts 做爲一個完整的套件!也就是說,假如你有兩支程序,一支爲 scripts1.sh 以及 scripts2.sh ,而 scripts2.sh 會去引用 scripts1.sh 的變數,這個時候,嘿嘿!你在 scripts1.sh 當中設定的變量請『千萬記得以 export 設定』, 否則你的變量將無法在兩個 scripts 之間互相被引用喔!當這個 scripts 執行完畢之後,剛剛在 scripts 當中設定的變量也就『失效了!』。 其實,要了解不同程序之間變量的變換,應該要先了解『程序』的概念比較好, 但是我們還沒有講到.....沒關係~等你念到程序章節後,還可以再回來好好的看一看。 基本上,環境變量可以讓子程序繼續引用的原因,是因爲:

    當啓動一個 shell ,操作系統分配一記憶區塊給 shell 使用,此區域之變量可以讓子程序存取;利用 export 功能,可以讓變量的內容寫到上述的記憶區塊當中(環境變量);當加載另一個 shell 時 (亦即啓動子程序,而離開原本的父程序了)子shell可以將父 shell 的環境變量所在的記憶區塊導入自己的環境變量區塊當中。












五    變量鍵盤讀取、數組與宣告: read, array, declare


我們上面提到的變量設定功能,都是直接由指令列直接設定的,那麼,可不可以讓使用者能夠經由鍵盤輸入? 什麼意思呢?是否記得某些程序執行的過程當中,會等待使用者輸入 "yes/no" 之類的訊息啊!? 在 bash 裏面也有相對應的功能喔!此外,我們還可以宣告這個變量的屬性, 例如:數組或者是數字等等的。底下就來看看吧!


read

要讀取來自鍵盤輸入的變量,就是用 read 這個指令了。這個指令最常被用在 shell script 的撰寫當中, 以跟使用者進行對談。關於 script 的寫法,我們會在後面章節介紹:

[root@linux ~]# read [-pt] variable
參數:
-p :後面可以接提示字符!
-t :後面可以接等待的『秒數!』這個比較有趣~不會一直等待使用者啦!


範例一:讓使用者由鍵盤輸入一內容,將該內容變成 atest 變量

[root@linux ~]# read atest
This is a test
[root@linux ~]# echo $atest
This is a test


範例二:提示使用者 30 秒內輸入自己的大名,將該輸入字符串做成 named 變量

[root@linux ~]# read -p "Please keyin your name: " -t 30 named
Please keyin your name: VBird Tsai
[root@linux ~]# echo $named
VBird Tsai

read 之後不加任何參數,直接加上變量名稱,那麼底下就會主動出現一個空白行,等待您輸入。 如果加上 -t 後面接秒數之後,例如上面的範例當中,那麼 30 秒之內沒有任何動作時, 該指令就會自動略過了~如果是加上 -p ,嘿嘿!後面就會有比較多可以用的提示字符給我們參考! 在指令的下達裏面,比較美觀啦! ^_^



declare / typeset


declare 或 typeset 是一樣的功能,就是在宣告變量的屬性。如果使用 declare 後面並沒有接任何參數, 那麼 bash 就會主動的將所有的變量名稱與內容通通叫出來,就好像使用 set 一樣啦! 那麼 declare 還有什麼語法呢?看看先:

[root@linux ~]# declare [-aixr] variable
參數:
-a :將後面的 variable 定義成爲數組 (array)
-i :將後面接的 variable 定義成爲整數數字 (integer)
-x :用法與 export 一樣,就是將後面的 variable 變成環境變量;
-r :將一個 variable 的變量設定成爲 readonly ,該變量不可被更改內容,也不能 unset


範例一:讓變量 sum 進行 100+300+50 的加總結果
[root@linux ~]# sum=100+300+50
[root@linux ~]# echo $sum
100+300+50 <==咦!怎麼沒有幫我計算加總?因爲這是文字型態的變量屬性啊!
[root@linux ~]# declare -i sum=100+300+50
[root@linux ~]# echo $sum
450 <==瞭乎??


範例二:將 sum 變成環境變量
[root@linux ~]# declare -x sum


範例三:讓 sum 變成只讀屬性,不可更動!
[root@linux ~]# declare -r sum
[root@linux ~]# sum=tesgting
-bash: sum: readonly variable <==老天爺~不能改這個變數了!
declare 也是個很有用的功能~尤其是當我們需要使用到底下的數組功能時, 他也可以幫我們宣告數組的屬性喔!不過,老話一句,數組也是在 shell script 比較常用的啦!


數組屬性 array 說明


在 bash 裏頭,數組的設定方式是:

var[index]=content

範例:設定上面提到的 var[1] ~ var[3] 的變數。

[root@linux ~]# var[1]="small min"
[root@linux ~]# var[2]="big min"
[root@linux ~]# var[3]="nice min"
[root@linux ~]# echo "${var[1]}, ${var[2]}, ${var[3]}"

比較有趣的地方在於『讀取』,一般來說,建議直接以 ${數組} 的方式來讀取, 比較正確無誤的啦!











六    與檔案系統及程序的限制關係: ulimit


想象一個狀況:我的 Linux 主機裏面同時登入了十個人,這十個人不知怎麼搞的, 同時開啓了 100 個檔案,每個檔案的大小約 10MBytes ,請問一下, 我的 Linux 主機的內存要有多大才夠? 10*100*10 = 10000爲了要預防這個情況的發生, bash 是可以『限制使用者的某些系統資源』的,包括可以開啓的檔案數量, 可以使用的 CPU 時間,可以使用的內存總量等等。


[root@linux ~]# ulimit [-SHacdflmnpstuv] [配額]

參數:
-H :hard limit ,嚴格的設定,必定不能超過設定的值;
-S :soft limit ,警告的設定,可以超過這個設定值,但是會有警告訊息,並且,還是無法超過 hard limit 的喔!也就是說,假設我的 soft limit爲 80 , hard limit 爲 100 ,那麼我的某個資源可以用到 90 ,可以超過 80 ,還是無法超過 100 ,而且在 80~90 之間,會有警告訊息的意思。

-a :列出所有的限制額度;
-c :可建立的最大核心檔案容量 (core files)
-d :程序數據可使用的最大容量
-f :此 shell 可以建立的最大檔案容量 (一般可能設定爲 2GB)單位爲 Kbytes
-l :可用於鎖定 (lock) 的內存量
-p :可用以管線處理 (pipe) 的數量
-t :可使用的最大 CPU 時間 (單位爲秒)
-u :單一使用者可以使用的最大程序(process)數量。


範例一:列出所有的限制數據
[root@linux ~]# ulimit -a


範例二:限制使用者僅能建立 1MBytes 以下的容量的檔案
[root@linux ~]# ulimit -f 1024

若改天你一直無法建立一個大容量的檔案,記得瞧一瞧 ulimit 的信息喔!( 不過,要注意的是,一般身份使用者如果以 ulimit 設定了 -f 的檔案大小, 那麼他『只能減小檔案大小,不能增加檔案大小喔!』)













七   其他額外的變量設定功能

剛剛我們提到了兩種變量取用的方法,分別是這樣:

[root@linux ~]# echo $HOME
[root@linux ~]# echo ${HOME}

那麼,在那個 ${variable} 的使用方法中,其實,我們還可以將變量進行一些修訂的工作喔! 只要加上一些字符標誌,後面再接着使用比對字符串,就能夠修改變量的內容了! 我們取底下的例子來說明:在底下的例子中,假設我的變量名稱爲 vbird ,且內容爲 /home/vbird/testing/testing.x.sh。


1. 完整呈現 vbird 這個變量的內容;
[root@linux ~]# vbird="/home/vbird/testing/testing.x.sh"
[root@linux ~]# echo ${vbird}
/home/vbird/testing/testing.x.sh


2. 在 vbird 變量中,從最前面開始比對,若開頭爲 / ,則刪除兩個/之間的

所有數據,亦即 /*/
[root@linux ~]# echo ${vbird##/*/}
testing.x.sh <==刪除了 /home/vbird/testing/
[root@linux ~]# echo ${vbird#/*/}
vbird/testing/testing.x.sh <==僅刪除 /home/ 而已
# 這兩個小例子有趣了~變量名稱後面如果接了兩個 ## ,表示在 ##
# 後面的字符串取『最長的』那一段;如果僅有一個 # ,表示取『最小的那一段』喔!


3. 承上題,如果是從後面開始,刪除 /* 呢?
[root@linux ~]# echo ${vbird%%/*/}
/home/vbird/testing/testing.x.sh <==都沒被刪除
[root@linux ~]# echo ${vbird%%/*}
<==被刪除光了!
[root@linux ~]# echo ${vbird%/*}
/home/vbird/testing <==只刪除 /testing.x.sh 部分
# 這個例子當中需要特別注意,那個 % 比對的是『最後面那個字符』的意思,
# 所以囉,第一個方式當然不對~因爲 vbird 這個變量的內容最後面是 h 而不是 / 啊!
# 至於 %%/* 則是刪除『最長的那個 /* 』,當然就是全部喔!而 %/* 則是最短的那個!


4. 將 vbird 變數中的 testing 取代爲 TEST
[root@linux ~]# echo ${vbird/testing/TEST}
/home/vbird/TEST/testing.x.sh
[root@linux ~]# echo ${vbird//testing/TEST}
/home/vbird/TEST/TEST.x.sh

# 如果變量後面接的是 / 時,那麼表示後面是進行『取代』的工作~而且僅取代『第一個』
# 但如果是 // ,則表示全部的字符串都取代啊!


這裏您稍微留意一下就好了~反正就是變量後面可以接 #, ##, %, %%, /, // , 而他們存在的意義並不相同的啦~ 





另外,幾個不同的變量內容還可以進行判斷呢! 舉例來說,目前我需要用到兩個變量,分別是 var 與 str , 那我想要針對 str 這個變量內容是否有設定成一個字符串,亦即 "expr" 來決定 var 的內容。 那我可以使用什麼方法來進行判斷呢?如果您會寫 shell script 的話, 直接用 shell script 就好了,如果不會寫,那麼我們就透過簡單的變量判斷吧!

Tips: 底下的例子當中,那個 var 與 str 爲變量,我們想要針對 str 是否有設定來決定 var 的值喔! 一般來說, str: 代表『str 沒設定或爲空的字符串時』;至於 str 則僅爲『沒有該變數』。


  變量設定方式            str沒有設定               str爲空字符串               str爲非空字符串



根據上面這張表,我們來進行幾個範例的練習吧! ^_^


範例一:若 str 這個變量內容存在,則 var 設定爲 str ,否則 var 設定爲 "newvar"

[root@linux ~]# unset str; var=${str-newvar}
[root@linux ~]# echo var="$var", str="$str"
var=newvar, str= <==因爲 str 不存在,所以 var 爲 newvar
[root@linux ~]# str="oldvar"; var=${str-newvar}
[root@linux ~]# echo var="$var", str="$str"
var=oldvar, str=oldvar <==因爲 str 存在,所以 var 等於 str 的內容


範例二:若 str 不存在,則 var 與 str 均設定爲 newvar,否則僅 var 爲 newvar

[root@linux ~]# unset str; var=${str=newvar}
[root@linux ~]# echo var="$var", str="$str"
var=newvar, str=newvar <==因爲 str 不存在,所以 var/str 均爲 newvar
[root@linux ~]# str="oldvar"; var=${str=newvar}
[root@linux ~]# echo var="$var", str="$str"
var=oldvar, str=oldvar <==因爲 str 存在,所以 var 等於 str 的內容


範例三:若 str 這個變量存在,則 var 等於 str ,否則輸出 "novar"

[root@linux ~]# unset str; var=${str?novar}
-bash: str: novar <==因爲 str 不存在,所以輸出錯誤訊息
[root@linux ~]# str="oldvar"; var=${str?novar}
[root@linux ~]# echo var="$var", str="$str"
var=oldvar, str=oldvar <==因爲 str 存在,所以 var 等於 str 的內容
# 上面這三個案例都沒有提到當 str 有設定,且爲空字符串的情況喔!
# 您可以自行測試一下哩!


雖然猛一看,覺得變量沒有什麼奇特的地方,但是,如果仔細瞧一瞧,嘿!一堆環境變量與系統資源方面的變量, 可是會影響到我們在 bash 裏頭是否能夠順利作業的呢!例如 PATH 啊、ulimit 之類的~ 所以,您還是得要了解變量這個玩意才行喔! ^_^


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章