shell腳本編程總結
shell是什麼;
Shell是系統的用戶界面,提供了用戶與內核進行交互操作的一種接口。它接收用戶輸入的命令並把它送入內核去執行。
實際上Shell是一個命令解釋器,它解釋由用戶輸入的命令並且把它們送到內核。不僅如此,Shell有自己的編程語言用於對命令的編輯,它允許用戶編寫由shell命令組成的程序。Shell編程語言具有普通編程語言的很多特點,比如它也有循環結構和分支控制結構等,用這種編程語言編寫的Shell程序與其他應用程序具有同樣的效果。
Linux提供了像MicrosoftWindows那樣的可視的命令輸入界面--X Window的圖形用戶界面(GUI)。它提供了很多桌面環境系統,其操作就像Windows一樣,有窗口、圖標和菜單,所有的管理都是通過鼠標控制。GNOME。
shell的種類
每個Linux系統的用戶可以擁有他自己的用戶界面或Shell,用以滿足他們自己專門的Shell需要。
同Linux本身一樣,Shell也有多種不同的版本。主要有下列版本的Shell: Bourne Shell:是貝爾實驗室開發的。
BASH:是GNU的Bourne Again Shell,是GNU操作系統上默認的shell。
Korn Shell:是對Bourne SHell的發展,在大部分內容上與Bourne Shell兼容。
C Shell:是SUN公司Shell的BSD版本。
Z Shell:The last shell you’ll ever need! Z是最後一個字母,也就是終極Shell。它集成了bash、ksh的重要特性,同時又增加了自己獨有的特性.
我們在系統上常用的shell是 bash
既然是編程,那麼編程所常有的概念,在shell中的體現是怎樣的呢?
事實上編程中所用到的變量,函數,數組,字符串,條件判斷, 循環結構在shell中都能體現.
shell腳本語法
第一行必須頂格寫並指明以下所使用的shell
#!/bin/bash
#!/usr/bin/python
#!/bin/tcsh
各種shell 如bash,python,tcsh任君選擇使用.
定義變量
shell語言是非類型的解釋型語言,強類型語言編程時需要事先聲明變量,並聲明其類型 shell編程中給一個變量賦值就是定義變量.
shell的變量是無類型的,所以用戶想讓它當字符時就是字符,想讓它當數字就是數字。
當然,我們還可以用 declare來指定其數據類型
declare
-r 只讀變量 =>相當於其它語言的常量吧,賦值後不能修改
-a 數組
-i 整型
-f 函數
在linux支持的所有shell中,都可以用賦值符號(=)爲變量賦值. 如:
abc=7 (不能在等號兩側留下空格 )
name=abc
在變量賦值之後,只需在變量前面加一個$去引用.
echo $abc
7
echo $name
abc
聲明只讀變量方法一
[robert@ca2 CA]$ declare -r nb=100
[robert@ca2 CA]$ nb=101
-bash: na: readonly variable =>當嘗試改變只讀變量的時候,系統會發出警告,提醒這是隻讀變量
聲明只讀變量之方法二 將變量變成常量[只讀變量]
[robert@ca2 CA]$ readonly na=100
[robert@ca2 CA]$ echo $na
100
[robert@ca2 CA]$ na=20
-bash: na: readonly variable =>當嘗試改變只讀變量的時候,系統會發出警告,提醒這是隻讀變量
shell腳本之條件判斷
有if語句作爲條件選擇分支
語法 if 條件判斷;then
執行語句
elif 條件判斷;then
執行語句
fi if條件判斷結束符
有case作爲條件選擇分支
#!/bin/bash
switch=6
case $switch in
[0-9])
echo $switch
;;
[a-z])
echo $switch
;;
esac
說到if語句結構,就得提及到條件測試
命令執行作爲條件測試依據
如grep 'root' /etc/passwd 將運行命令成功與否作爲判斷條件
if grep 'root' /etc/passwd;then
echo "root 用戶存在"
else
echo "root 用戶不存在"
fi
shell腳本之 case選擇分支
比較運算:
>, <, >=, <=, ==, !=
條件判斷中,存在各種判斷, 各種測試類型如下
測試類型:根據比較時的操作數的類型
整型測試:整數比較
字符測試:字符串比較
文件測試:判斷文件的存在性及屬性等
注意:比較運算通常只在同一種類型間進行
整型測試:
-gt: 例如 [ $num1 -gt $num2 ]
-lt:
-ge:
-le:
-eq:
-ne:
字符串測試:
雙目
>: [[ "$str1" > "$str2" ]]
<:
>=
<=
==
!=
單目:
-n String: 是否不空,不空則爲真,空則爲假
-z String: 是否爲空,空則爲真,不空則假
bash條件測試之文件測試:
-a file
True if file exists.
-b file
True if file exists and is a block special file.
-c file
True if file exists and is a character special file.
-d file
True if file exists and is a directory.
-e file
True if file exists.
-f file
True if file exists and is a regular file.
-g file
True if file exists and is set-group-id.
-h file
True if file exists and is a symbolic link.
-k file
True if file exists and its ''sticky'' bit is set.
-p file
True if file exists and is a named pipe (FIFO).
-r file
True if file exists and is readable.
-s file
True if file exists and has a size greater than zero.
-t fd True if file descriptor fd is open and refers to a terminal.
-u file
True if file exists and its set-user-id bit is set.
-w file
True if file exists and is writable.
-x file
True if file exists and is executable.
-O file
True if file exists and is owned by the effective user id.
-G file
True if file exists and is owned by the effective group id.
-L file
True if file exists and is a symbolic link.
-S file
True if file exists and is a socket.
-N file
True if file exists and has been modified since it was last read.
file1 -nt file2
True if file1 is newer (according to modification date) than file2, or if file1 exists and file2 does not.
file1 -ot file2
True if file1 is older than file2, or if file2 exists and file1 does not.
file1 -ef file2
True if file1 and file2 refer to the same device and inode numbers.
-o optname
True if shell option optname is enabled. See the list of options under the description of the -o option to the set builtin
below.
-a FILE
-e FILE: 存在則爲真;否則則爲假;
-f FILE: 存在並且爲普通文件,則爲真;否則爲假;
-d FILE: 存在並且爲目錄文件,則爲真;否則爲假;
-L/-h FILE: 存在並且爲符號鏈接文件,則爲真;否則爲假;
-b: 塊設備
-c: 字符設備
-S: 套接字文件
-p: 命名管道
-s FILE: 存在並且爲非空文件則爲值,否則爲假;
-r FILE
-w FILE
-x FILE
file1 -nt file2: file1的mtime新於file2則爲真,否則爲假;
file1 -ot file2:file1的mtime舊於file2則爲真,否則爲假;
shell腳本之for in 循環
格式 for 變量 in 集合;do 語句體 ; done 循環結束標識
詳細案例如下
declare -i sum=0
for i in {1..9};do
let sum+=$i //sum=$[$sum+$i] 中括號相加
done
echo $sum
let計算
shell腳本之for 循環
#!/bin/bash
for ((i=0;$i<10;i++));do
echo $i
done
shell腳本之while 循環
num=0
while true ;do
let num++
if [ $num -gt 10 ];then
break
fi
done
echo $num
shell腳本之until 循環 ==>與while循環不同的是,until的條件判斷中,條件不成立,循環會繼續進行
num=0
until [ $num -gt 10 ];do
let num++
done
echo $num
shell 腳本之函數使用
function test {
echo "$1 do you want test function"
}
test 'robert'
shell腳本之數組
數組是編程中,存儲控制數據非常重要的一個手段和方式,但遺憾的是 linux的shell只支持一維數組
數組其實也是一種變量,不同的是,這個特殊類型的變量內,還可以存其它的變量.
數組的使用
數組名+索引
數組元素
索引的表示方式:
數字索引:a[index]
a[0], a[1]
bash 4.0的關聯數組
a[hello], a[hi]
declare -a 索引數組
-A 關聯數組
支持稀疏格式:
數組的賦值:
一次對一個元素賦值:
a[0]=0
a[1]=1
a[2]=2
a[3]=3
直接賦值:
arr=(0 1 2 3)
按索引進行賦值:
a=([0]=0 [3]=3 [2]=2 [1]=1)
用戶輸入:
read -a arr 用戶輸入的方式生成數組
數組的訪問:
用索引訪問:
ARRAY[index]
如 a=([0]=0 [3]=3 [2]=2 [1]=1)
echo a[0]訪問索引爲0的數組
0 ==>結果爲0
數組的長度:
[robert@ca2 ~]$ array=([0]=0 [3]=3 [2]=2 [1]=1)
[robert@ca2 ~]$ echo ${#array[@]}
4
從數組中挑選某元素:
${ARRAY[@]:offset:number}
切片:
offset: 偏移的元素個數
number: 取出的元素的個數
[robert@ca2 ~]$ array=([0]=0 [3]=3 [2]=2 [1]=1)
[robert@ca2 ~]$ echo ${array[@]:1:2}
1 2
${ARRAY[@]:offset}:取出偏移量後的所有元素
[robert@ca2 ~]$ echo ${array[@]:1}
1 2 3
${ARRAY[@]}: 取出所有元素
[robert@ca2 ~]$ echo ${array[@]}
0 1 2 3
使用@和*的不同
$@: 每個參數是一個獨立的串
$*: 所有參數是一個串
數組如果想作爲對數傳入給函數使用,怎麼辦呢?
#!/bin/bash
function myarr {
#echo $@
#exit 0
newarr=(echo "$@") 接收時轉化爲數組
echo ${newarr[@]}
}
myarray=(12 23 34 45)
myarr ${myarray[@]} ==>注,爲函數傳遞數組作爲變量,需要注意,要將其轉化爲N個參數傳入
在編程中,字符串的操作是相當頻繁常用的
字符串
字符串切片:
${string:offset:length} 從左向右取,依稀量,加長度, 如果只指定偏移量,則偏移後,取所有字串
取尾部的指定個數的字符:
${string: -length} 加個 " - " 號,則是從右向左取
取子串:基於模式
${variable#*word}:在variable中存儲字串上,自左而右,查找第一次出現word,刪除字符開始至此word處的所有內容;
[root@localhost ~]# url=www.baidu.com
[root@localhost ~]# echo $url
www.baidu.com
[root@localhost ~]# echo ${url#*.} 從左到右,取第一次出現的.號,並從左開始第一個字符刪除到第一次出現的字符,
baidu.com
[root@localhost ~]# echo ${url##*.} 再加一個# 是貪婪模式,找到從左到右,最後一次出現的 . 並從頭到 . 刪除
com
${variable##*word}:在variable中存儲字串上,自左而右,查找最後一次出現word,刪除字符開始至此word處的所有內容;
file='/var/log/messages'
${file#*/}: 返回的結果是var/log/messages
${file##*/}: 返回messages
${variable%word*}: 在variable中存儲字串上,自右而左,查找第一次出現word,刪除此word處至字串尾部的所有內容;
${variable%%world*}:在variable中存儲字串上,自右而左,查找最後一次出現word,刪除此word處至字串尾部的所有內容;
file='/var/log/messages'
${file%*/}: 返回的結果是/var/log
${file%%*/}: 返回結果爲空
phonenumber='010-110-8'
${phonenumber%%-*}
${phonenumber##*-}
url="http://www.magedu.com:80"
遍歷訪問一個字符串(默認是以空格分開的,當字符串是由其他字符分隔時可以參考 2)
#!/bin/bash
str="a --m"
for i in $str
do
echo $i
done
array
聲明數組 myarray=(1 2 3 )
打印數組 echo ${myarray[@]}
1 2 3
訪問數組的長度 ${#myarray[@]}
[root@localhost ~]# echo ${#myarray[@]}
3
#直接輸出的是數組的第一個元素
echo $array
#用下標的方式訪問數組元素
echo ${array[1]}
#輸出這個數組
echo ${array[@]}
#輸出數組中下標爲3的元素的長度
echo ${#array[3]}
#輸出數組中下標 爲1到3的元素
echo ${array[@]:1:3}
#輸出數組中下標大於2的元素
echo ${array[@]:2}
#輸出數組中下標小於2的元素
echo ${array[@]::2}
字符串
字符串切片:
${string:offset:length} 從左向右取,依稀量,加長度, 如果只指定偏移量,則偏移後,取所有字串
取尾部的指定個數的字符:
${string: -length} 加個 " - " 號,則是從右向左取
取子串:基於模式
${variable#*word}:在variable中存儲字串上,自左而右,查找第一次出現word,刪除字符開始至此word處的所有內容;
[root@localhost ~]# url=www.baidu.com
[root@localhost ~]# echo $url
www.baidu.com
[root@localhost ~]# echo ${url#*.} 從左到右,取第一次出現的.號,並從左開始第一個字符刪除到第一次出現的字符,
baidu.com
[root@localhost ~]# echo ${url##*.} 再加一個# 是貪婪模式,找到從左到右,最後一次出現的 . 並從頭到 . 刪除
com
${variable##*word}:在variable中存儲字串上,自左而右,查找最後一次出現word,刪除字符開始至此word處的所有內容;
file='/var/log/messages'
${file#*/}: 返回的結果是var/log/messages
${file##*/}: 返回messages
${variable%word*}: 在variable中存儲字串上,自右而左,查找第一次出現word,刪除此word處至字串尾部的所有內容;
${variable%%world*}:在variable中存儲字串上,自右而左,查找最後一次出現word,刪除此word處至字串尾部的所有內容;
file='/var/log/messages'
${file%*/}: 返回的結果是/var/log
${file%%*/}: 返回結果爲空
phonenumber='010-110-8'
${phonenumber%%-*}
${phonenumber##*-}
url="http://www.magedu.com:80"
遍歷訪問一個字符串(默認是以空格分開的,當字符串是由其他字符分隔時可以參考 2)
#!/bin/bash
str="a --m"
for i in $str
do
echo $i
done
1.長度
[root@localhost ~]$ test='I love china'
[root@localhost ~]$ echo ${#test}
12
${#變量名}得到字符串長度
2.截取字串
[root@localhost ~]$ test='I love china'
[root@localhost ~]$ echo ${test:5}
e china
[root@localhost ~]$ echo ${test:5:10}
e china
${變量名:起始:長度}得到子字符串
3.字符串刪除
[root@localhost ~]$ test='//tmp/boot.ini'
[root@localhost ~]$ echo ${test#/}
/tmp/boot.ini
[root@localhost ~]$ echo ${test#*/}
/tmp/boot.ini
[root@localhost ~]$ echo ${test##*/}
boot.ini
[root@localhost ~]$ echo ${test%/*}
c:/windows
[root@localhost ~]$ echo ${test%%/*}
${變量名#substring正則表達式}從字符串開頭開始配備substring,刪除匹配上的表達式。
${變量名%substring正則表達式}從字符串結尾開始配備substring,刪除匹配上的表達式。
注意:${test##*/},${test%/*} 分別是得到文件名,或者目錄地址最簡單方法。
4.字符串替換
[chengmo@localhost ~]$ test='/tmp/boot.ini'
[chengmo@localhost ~]$ echo ${test/\//\\}
/tmp/boot.ini
[chengmo@localhost ~]$ echo ${test//\//\\}
/tmp/boot.ini