一、什麼是shell?
shell是處於用戶和Linux系統之間的命令解釋器。
二、shell基礎操作
1.創建shell腳本
vi first_shell.sh
2.shell腳本的格式
#!/bin/bash
#filename:first_shell
#created day:2019.9.28
echo "Hello World!"
第一行:#!/bin/bash
#!是一種約定標記,他告訴系統這個腳本需要用/bin/bash解釋器來執行,如果不寫這一行腳本也可以執行,只是系統會根據自身的shell解釋器來解釋腳本。
第二和第三行
shell腳本使用#來標識註釋。
第四行:echo “Hello World!”
shell將沒有#標識的語句解釋爲命令。
shell腳本的命令語句可以在行末使用;
表示結束,也可以不適用,但是一行有多條語句必須使用;
分隔。
3.執行腳本
/bin/bash first_shell.sh
輸出結果:
Hello World!
三、變量
1.局部變量
shell中沒有特別標註的變量都屬於局部變量,如:
#!/bin/bash
#by goulandis 2019.9.28
A="asd"
echo $A
A=123
echo $A
局部變量只能在腳本內部才能使用。
shell是非類型的解釋型語言,變量的類型在運行事確定。
字符串也可以不要使用""
,如:A=asd
,輸出結果也是一樣的,但是不使用""
賦值時,字符串之間不能出現空格,如:A=a s d
這樣賦值會報錯。
輸出結果:
asd
123
變量的使用
shell中直接使用$加變量名的組合即可使用變量,如:echo $A
需要注意的是:在給變量賦值時不能出現空格,如:A = 123,這樣的語法shell無法識別,必須爲:A=123,纔可以。
2.環境變量
環境變量可以在腳本內也可以在其他的腳本中使用,即在系統環境中都可以使用。
變量名 | 作用 |
---|---|
$0 | 存儲當前腳本的名字 |
$n | n是一個數字,存儲傳遞給腳本的迪n個變量 |
$# | 存儲傳遞給腳本的參數的數量 |
$* | 存儲傳遞給腳本的所有的參數 |
$@ | 用法和$*一樣// |
$? | 存儲上一個命令的退出狀態,命令執行成功返回0,否則返回錯誤碼 |
$$ | 存儲當前shell腳本所在進程的ID |
$UID | 存儲當前用戶ID |
$PWD | 存儲當前所在路徑 |
示例:
注:
echo -e "\033[32m"
可以修改其後的輸出字體的顏色。
echo -e "\033[0m"
結束字體顏色修改。
字體設置詳情請前往:https://blog.csdn.net/andylauren/article/details/60873400
輸出時可以使用\來進行字符轉義
3.變量的命名規則
shell
的變量的命名規則基本和C是一致的,並且shell大小寫敏感。
四、語句結構
1.if條件語句
普通結構
if((num1>num2))
then
echo "$num1>$num2"
else
echo "$num1<$num2"
fi
和其他語言不同的是,shell中條件判斷分支語句不能爲空,即不能出現如下情況:
if((num1>num2))
then
echo "$num1>$num2"
else
fi
如此編譯將無法通過。
這裏有幾點須要注意:
- if後面更的必須是雙括號(()),使用單括號會報錯,使用(())變量可以直接使用變量名來使用,而不需要通過來引用變量,否則也會報錯;
使用雙括號:**
a=10
b=20
if((a>b))
then
echo "$a > $b"
else
echo "$a < $b"
fi
使用中括號(不使用空格分隔):
這裏有一個錯誤,即if[a>b]應該改爲if[b]。
使用中括號(使用空格分隔):
-
一行中的多條語句須要使用;進行分隔;如:
if((num1>num2));then echo "$num1>$num2" fi
-
if語句必須使用fi進行結尾,告知解釋器if語句的結束;
嵌套結構
#!/bin/bash
#by goulandis 2019.9.29
if [[ $1 -gt 90 ]];then
echo "every good"
elif [[ $1 -gt 80 ]];then
echo "good"
elif [[ $1 -gt 60 ]];then
echo "pass"
else
echo "no pass"
fi
這裏須要注意,每一個if和elif語句後面都必須跟一個then。
邏輯運算符
shell中除了可以使用“+,-,*,/,%,^,>,>=,==,<,<=,!”等編程常用的運算符外,還可以使用字母代替部分運算符。
運算符 | 作用 |
---|---|
-f | 判斷文件是否存在 eg: if [ -f filename ] |
-d | 判斷目錄是否存在 eg: if [ -d dir ] |
-eq | 等於,整型比較 |
-ne | 不等於,整型比較 |
-lt | 小於,整型比較 |
-gt | 大於,整型比較 |
-le | 小於或等於,整型比較 |
-ge | 大於或等於,整型比較 |
-a | 邏輯與 eg: 邏輯表達式 -a 邏輯表達式 |
-o | 邏輯或 eg: 邏輯表達式 -a 邏輯表達式 |
-z | 空字符串 |
如向文件中寫入內容:
第一次執行/bin/bash var.sh asd:創建文件text.txt並向文件中寫入傳入的第一個參數內容;
第二次執行/bin/bash var.sh asd:文件已存在,所以直接cat文件內容。
(())、[]、[[]]的區別
在寫shell腳本時,常碰到(())、[]、[[]],這裏來看看三者之間的區別:
符號 | 區別 |
---|---|
(()) | (())的作用基本和let一致,(())主要用於算術運算,比較適合進行整數比較,可以直接通過變量名來引用變量,而不需要通過$,只可以使用數學運算符“>,<,==”等進行比較; |
[] | []的作用與test一致,[]不支持數學運算符,只能使用字符運算符“-ge,-lt”等,[]支持“和!=”,但是“”,“!=”在[]中只能用於字符串的比較; |
[[]] | [[]]的功能比[]要強大,[[]]的用法和[]一樣,但是[[]]支持邏輯組合“&&,||” |
小知識:
- 用反引號包含的語句可以當作命令解釋。如:
shell解釋器會將反引號內的字符串解釋爲一個命令(如果命令有效則執行,如果無效則報錯),而不是當作字符串。
組合與&&不止可以組合邏輯表達式,還可以組合命令語句,並且組合命令語句時,當前面的語句執行失敗,後面的語句將不執行。而組合或||則是無論前面的語句是否執行成功都會執行後面的語句。
2.for循環
普通結構
j=0
for((i=1;i<=100;i++))
do
j=`expr $i + $j`
done
echo $j
輸出結果:
goulandis@ubuntu:~/shell$ /bin/bash var.sh
5050
小知識:
- 這裏的循環語句使用的是j=`expr $i + $j`,因爲必須告知解釋器要將
expr $i + $j
解釋爲命令,否則解釋器會將expr $i + $j
當作是字符串。 - expr命令的作用是求兩個數的和。
- 在執行腳本時,添加參數
-x
可以查看腳本運行的過程,如:/bin/bash -x var.sh
for in
結構
cd /home/goulandis/shell/tmp
dir=/home/goulandis/shell
for file in $(ls *)
do
mv $file $dir
done
file
的值從$(ls *)
中依次獲取,$file
即獲取file
的值; 循環語句放在do和done之間。
for in
結構的好處在於,可以從一個命令的輸出集合裏自動讀取集合裏的數據。、
‘’、""的區別
兩者都是爲了解決字符串中間有空格的情況,''
剝奪了字符串的所有含義,在''
內的任何字符都只被解釋爲字符,而""
則保留了一些參數如:$、``、\。
小知識:
-
$(ls *)
可以獲取當前目錄下的所有文件 -
$(ls split*)
可以獲取當前目錄下的所有子目錄
3.while循環
while read line
do
echo $line
done < /home/goulandis/shell/var.sh
i=0
while ((i<5))
do
echo $i
((i++))
done
輸出語句:
#!/bin/bash
#by goulandis 2019.9.28
while read line
do
echo $line
done < /home/goulandis/shell/var.sh
i=0
while ((i<5))
do
echo $i
((i++))
done
0
1
2
3
4
-
while
之後可以跟命令語句(如:reas line
),也可以更邏輯表達式(如:i<5
),但是邏輯表達式必須使用(())
括起來,並且while
的遞增變量也必須使用(())
括起來。 - 和
for
一樣,while
的循=循環體必須放在do done
之間。
小知識:
-
read
命令配合< 文件名
可以讀取文件裏的內容。如:讀取host.txt文件的第二列的內容文件內容:
1 Alian man 176
2 Goulandis faleman 168
3 Dekes man 188
操作代碼:
while read line
do
name=`echo $line | awk '{print $2}'`
echo -e "\033[32mName:$name\033[0m"
done <host.txt
讀取結果:
goulandis@ubuntu:~/shell$ /bin/bash var.sh
Name:Alian
Name:Goulandis
Name:Dekes
4.until循環
i=5
until [[ i -lt 0 ]]
do
echo $i
((i--))
done
輸出結果:
goulandis@ubuntu:~/shell$ /bin/bash var.sh
5
4
3
2
1
0
與while
當滿足條件時執行不同的是,until
是當滿足條件時退出;
和所有循環體一樣,until
的循環體也放在do done
中。
5.case條件語句
case $1 in
apache)
echo "Install Apache"
;;
mysql)
echo "Install mysql"
;;
php)
echo "Install php"
;;
*)
echo "usage:{$0 apache|mysql|php|help}"
;;
esac
-
case
語句必須使用esac
標識語句結束 - 每一個分支的匹配值後面是必須跟一個
)
的 - 每一個分支也必須使用
;;
進行分隔 - 不像C++中的
switch
語句沒有break
不跳出而繼續向下執行,shell
中的case
語句執行完分支後會自動跳出 -
*
表示當分支中沒有能比配的值時,就匹配*
這個分支
6.select語句
select
語句的主要功能就是自動生成一個選擇菜單
PS3="select application number:"
select i in "apache" "mysql" "php"
do
case $i in
apache)
echo "install apache"
;;
mysql)
echo "install mysql"
;;
php)
echo "install php"
;;
*)
echo "usage:{input 1|2|3|help}"
esac
done
輸出結果:
goulandis@ubuntu:~/shell$ /bin/bash var.sh
1) apache
2) mysql
3) php
select application number:1
install apache
-
in
後面可以跟一系列的鍵值集合,每個鍵值之間使用空格分隔 -
shell
預定義了變量PS3
(大寫的PS3)用於輸入描述,如:輸出結果中的select application number:
-
select
和case
搭配能形成十分友好的選擇界面 -
select
的語句體也必須放在do done
中間
五、數組
1.一維數組
數組定義
A=(1 2 3)
數組使用
echo ${A[0]}
shell的數組也是從0號索引開始
幾種數組的常用方法
方法 | 作用 |
---|---|
${A[@]}或${A[*]} |
顯示所有元素 |
${#A[@]} |
統計數組的參數個數 |
${A[@]/1/a} |
替換數組元素 |
unset A[n] |
刪除數組中第n個元素 |
數組的賦值
直接初始化時賦值
A=(
apache
mysql
php
)
一個元素一個元素的賦值
#A=()可寫也可不寫
A=()
A[0]=0
A[1]=1
六、函數
函數定義
function command()
{
#函數體
}
函數調用
command 參數列表
參數列表按順序依次對應$1,$2,$3等,如:
function command()
{
if [[ (! -z $1) && (! -z $2) ]]
then
echo $1 $2
fi
}
command param1 param2
輸出結果:
goulandis@ubuntu:~/shell$ /bin/bash var.sh
param1 param2
這裏要注意使用&&
時一個邏輯表達式需要用()
括起來,否則&&
會將$1
與!
進行&&
運算。
函數的返回值
函數用return
來返回值,但是return
只能用於返回整型,返回字符串需要用echo
。如:
#返回數字-方法1
function command()
{
if(($1==1));then
return $1
else
echo $1
fi
}
command 1
echo $?
#返回數字-方法2
echo $command 1
#返回字符串-方法1
echo $(command asd)
#返回字符串-方法2
echo `command sdf`
輸出結果:
goulandis@ubuntu:~/shell$ /bin/bash var.sh
1
1
asd
sdf
$?
接收上一句命令的返回值。
小知識:
read -p "輸入描述" cmd
命令可以記錄命令命令行的輸入到cmd變量中,如:
goulandis@ubuntu:~/shell$ read -p "Input parameter:" cmd
Input parameter:this a command
goulandis@ubuntu:~/shell$ echo $cmd
this a command
七、shell命令
1.sed命令
示例:對如下sed.txt文件進行修改
#by auther 2019.9.30 txt
ip 192.168.9.120
ip 192.168.5.5
ip 168.1.2.111
those my ip
替換字符串
sed -i 's/auther/goulandis/g' sed.txt
輸出結果:
#by goulandis 2019.9.30 txt
ip 192.168.9.120
ip 192.168.5.5
ip 168.1.2.111
those my i
將sed.txt
中的所有auther
字符串替換成字符串goulandis
,其中開頭的s
和結尾的g
是必須寫的,這是固定格式,並且參數-i
也是必須寫的,如果不使用參數-i
則sed
只會修改緩衝區中的數據,而不會修改sed.txt
源文件中的內容。
在行首/行尾插入
sed -i 's/^/&line /g' sed.txt
輸出結果:
line #by goulandis 2019.9.30 txt
line
line ip 192.168.9.120
line ip 192.168.5.5
line ip 168.1.2.111
line
line those my ip
在sed.txt
的每行行首插入字符串line
,行首匹配規則使用的是正則表達式
,若需要在行尾插入,命令爲sed -i 's/$/&字符串/g' sed.txt
。
在前一行或後一行插入
sed -i '/192.168.9.120/a line ip 192.168.9.9' sed.txt
輸出結果:
line #by goulandis 2019.9.30 txt
line
line ip 192.168.9.120
line ip 192.168.9.9
line ip 192.168.5.5
line ip 168.1.2.111
line
line those my ip
在sed.txt
的192.168.9.120
所在行的後面一行插入字符串line ip 192.168.9.9
,這裏要注意,這個命令不再寫前面的s
和後面的g
,如果要在前面一行插入,則將a
替換成i
。
打印固定行數的內容
sed -n '1,3p' sed.txt
輸出結果:
line #by goulandis 2019.9.30 txt
line
line ip 192.168.9.120
打印sed.txt
中第一行到第三行的內容,其中p
是必須寫的 ,打印首行和尾行sed -n '1p;$p' sed.txt
。
這裏要注意,'1,$p'
表示從首行到尾行,有多行,'1p;$p'
表示首行和尾行,只有兩行。
2.find命令
尋找文件
find . -name "sed.txt"
在當前目錄下尋找文件sed.txt
。
find . -maxdepth 1 -name "sed.txt"
在當前目錄一級目錄下搜索sed.txt
文件,即不向子目錄搜索。
find . -maxdepth 1 -type f -name "*.txt" -mtime -1
在當前目錄一級目錄下搜索類型爲文件,修改時間爲1天前的txt
文件。
find . -maxdepth 1 -type f -name "*.txt" -mtime -1 -exec rm -rf {} \;
在當前目錄一級目錄下搜索類型爲文件,修改時間爲1天前的txt
文件並刪除這些文件。-exec
表示將前面搜索到的內容放到{}
中。其中\;
是必須的固定格式。-xargs
的作用和-exec
基本一樣,只是-xargs
不能配合cp
和mv
命令使用。
3.grep命令
搜索固定內容的行
grep "ip" sed.txt
輸出結果:
line ip 192.168.9.120
line ip 192.168.9.9
line ip 192.168.5.5
line ip 168.1.2.111
line those my ip
使用參數-v
表示反義,如:grep -v "ip" sed.txt
,表示搜索不包含ip
的行。-n
可以將行號一併打印出來。
grep "120$" sed.txt
搜索以120
結尾的行,開頭使用"^line"
,""
中寫入正則表達式,即可按正則表達式來搜索內容。
4.awk命令
打印列
awk '{print "註解:" $1}' sed.txt
打印第一列的內容,列之間需要用空格分隔,否則將識別成一列,$n
表示第n列。$NF
表示最後一列,""
中可以在輸出內容前添加任何註解。